FORMS

File Upload Input

A modern file upload input with a clean dark design, custom upload button, and selected file name display.

No file selected
HTML
<div class="file-upload">

  <input
    type="file"
    id="file-upload-input"
    data-file-input
  >

  <label
    for="file-upload-input"
    class="file-upload-button"
  >

    <svg viewBox="0 0 24 24" aria-hidden="true">
      <path d="M12 16V4"></path>
      <path d="M7 9l5-5 5 5"></path>
      <path d="M5 20h14"></path>
    </svg>

    <span>Choose File</span>

  </label>

  <span
    class="file-upload-name"
    data-file-name
  >
    No file selected
  </span>

</div>
CSS
.file-upload{
  display:flex;
  align-items:center;
  gap:14px;
  flex-wrap:wrap;
}

.file-upload input{
  position:absolute;
  width:1px;
  height:1px;
  opacity:0;
  overflow:hidden;
}

.file-upload-button{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:9px;

  min-height:46px;
  padding:0 18px;

  border:1px solid #22d3ee;
  border-radius:9px;

  background:#0b1423;
  color:#ffffff;

  font-size:14px;
  font-weight:700;

  cursor:pointer;

  transition:.25s ease;
}

.file-upload-button svg{
  width:18px;
  height:18px;

  fill:none;
  stroke:#22d3ee;
  stroke-width:2;
  stroke-linecap:round;
  stroke-linejoin:round;
}

.file-upload-button:hover{
  background:#101c2e;

  box-shadow:
    0 0 18px rgba(34,211,238,.18);
}

.file-upload-name{
  color:#8190a5;
  font-size:14px;
}
JavaScript
const fileInput = document.querySelector('[data-file-input]');
const fileName = document.querySelector('[data-file-name]');

fileInput.addEventListener('change', function() {

  if (fileInput.files.length) {
    fileName.textContent = fileInput.files[0].name;
  } else {
    fileName.textContent = 'No file selected';
  }

});

How This File Upload Input Works

The File Upload Input replaces the browser’s visible file control with a custom-styled button while keeping a real <input type="file"> in the HTML. The component contains three main pieces: the native file input, a label styled as the “Choose File” button, and a text element that displays either the selected filename or the default “No file selected” message.

The actual file input uses position: absolute, dimensions of 1px by 1px, and opacity: 0. This makes the browser control visually hidden while leaving it in the document. Instead of clicking the input directly, the user interacts with the <label> whose for="file-upload-input" value matches the input’s id. That association makes clicking the custom label open the browser’s native file picker.

The .file-upload wrapper uses Flexbox with align-items: center, a 14px gap, and flex-wrap: wrap. The wrapping behavior is useful when horizontal space becomes limited because the filename can move to another line rather than forcing the entire component to stay on one row.

The custom .file-upload-button is an inline-flex element with a minimum height of 46px and horizontal padding of 18px. It has a 1px cyan #22d3ee border, 9px rounded corners, and a dark #0b1423 background. An inline SVG creates the upload icon rather than relying on an image file or external icon library. Its paths use a cyan stroke with rounded line caps and joins.

Hovering over the button changes its background to #101c2e and adds a subtle cyan glow using box-shadow: 0 0 18px rgba(34,211,238,.18). The .25s ease transition smooths this visual change.

JavaScript is responsible for displaying the selected filename. It finds the file input through [data-file-input] and the filename element through [data-file-name]. A change event listener runs whenever the file selection changes.

Inside that listener, the code checks fileInput.files.length. If at least one file exists, it reads the first item with fileInput.files[0].name and assigns that filename to the text element. If no file is selected, the text returns to “No file selected.” For more information about accessing files chosen through a file input, see the MDN FileList documentation.

The component is designed for one file at a time. There is no multiple attribute on the input, and the JavaScript specifically displays the name of files[0]. It also does not upload the selected file to a server. The code only opens the native file picker and reflects the chosen filename in the interface.

Customizing the File Upload Input

The component has a small set of CSS values that can be adjusted to match different forms and interface styles.

  • Change the 14px .file-upload gap to control spacing between the button and filename.
  • Edit the button’s min-height: 46px and padding: 0 18px to create a smaller or larger control.
  • Change #22d3ee to customize the button border and SVG icon color.
  • Replace the #0b1423 background and #101c2e hover background to match another color scheme.
  • Adjust the 9px border radius to make the button sharper or more rounded.
  • Change the SVG width and height from 18px to resize the upload icon.
  • Modify the .25s ease transition and cyan hover shadow to change the interaction feedback.
  • Edit the #8190a5 color or 14px font size of .file-upload-name to change how the selected filename appears.

Where to Use This File Upload Input

This component fits forms where a native file picker is required but the default browser control does not match the rest of the interface.

  • Contact forms with attachment fields
  • Resume and CV submission forms
  • Profile image selection interfaces
  • Document submission pages
  • Support ticket attachment fields
  • Application and registration forms
  • Dashboard file-selection controls

For a basic form that collects a user’s name, email, and message, the Contact Form is a related CodeRipple component that can be paired conceptually with this file-selection control. An actual upload workflow would still require form submission or JavaScript that transfers the selected file to a server or storage service.

Frequently Asked Questions

Does this component actually upload the selected file?

No. It lets the user select a file and displays its filename. There is no form submission, upload request, API call, or server-side storage logic in the current component.

Why is the real file input hidden?

The native input remains responsible for opening the browser’s file picker, but CSS reduces it to 1px by 1px and makes it transparent. The associated label provides the visible custom button.

Can users select multiple files with this component?

No. The file input does not contain the multiple attribute, and the JavaScript only reads fileInput.files[0]. The current implementation is intended for a single selected file.

What happens if no file is selected?

The filename area displays “No file selected.” When a file exists, the JavaScript replaces that text with the selected file’s .name value.

The File Upload Input keeps the native browser file-selection behavior while using CSS for the visible control and a short JavaScript listener to provide immediate filename feedback.

Scroll to Top