DEV Community 👩‍💻👨‍💻

DEV Community 👩‍💻👨‍💻 is a community of 966,904 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Abdulqudus Abubakre
Abdulqudus Abubakre

Posted on

Styling file inputs like a boss

HTML elements have default styles applied to them by individual browsers. These styles could vary depending on the browser, and applying your own custom styles could range from being very easy to unnecessarily complicated (sometimes impossible).

In this article we would be going through how to style file inputs, which happens to be one of those difficult elements to style using CSS.

If you've worked with file inputs in your application, you'd know that the default style doesn't look so nice. Here's an example of how it looks in chrome and firefox in case you're wondering.

Default file inputs in firefox and chrome

The good news is, we can fix this...the bad news is we won't be able to use the "conventional" method.

Styling File Inputs

Let's create a simple file input in our HTML.

<div class="file-input">
  <input type="file" id="file" class="file">
  <label for="file">Select file</label>
</div>
Enter fullscreen mode Exit fullscreen mode

To style a file input, the first thing we would need to do is get rid of the default file input.

Hiding the input

.file {
  opacity: 0;
  width: 0.1px;
  height: 0.1px;
  position: absolute;
}
Enter fullscreen mode Exit fullscreen mode

You might be thinking, why not use display: none to hide the input. Well the problem with that is the input field would be removed from the layout and then become inaccessible to people using screen readers which would be very bad.

Another important thing to note is the label. With file inputs, clicking on the label also opens up the file picker, so we can use that to our advantage and style the label anyway we want.

Styling the label

Now that we've hidden the default input, we can decide to style the label however we want. For simplicity sake, let's just make it look like a button.

.file-input label {
  display: block;
  position: relative;
  width: 200px;
  height: 50px;
  border-radius: 25px;
  background: linear-gradient(40deg, #ff6ec4, #7873f5);
  box-shadow: 0 4px 7px rgba(0, 0, 0, 0.4);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-weight: bold;
  cursor: pointer;
  transition: transform .2s ease-out;
}
Enter fullscreen mode Exit fullscreen mode

Styled input with purple gradient

Accessibility

So we've been able to style the label to look like a button, but that's not all. We need to add some sort of indications to the label for when people hover on the field, or try to focus on the file field using the keyboard. I'm just going to do something simple here and increase the size of the label when that happens.

input:hover + label,
input:focus + label {
  transform: scale(1.02);
}
Enter fullscreen mode Exit fullscreen mode

We can also decide to add an outline to the label on focus

input:focus + label {
  outline: 1px solid #000;
  outline: -webkit-focus-ring-color auto 2px;
}
Enter fullscreen mode Exit fullscreen mode

The -webkit-focus-ring-color is used to get the default outline look on webkit browsers like chrome or safari. For non webkit browsers, a black outline would be applied to the element.

Javascript Enhancements

We can use JavaScript to display the name and size of the file selected. This would create a slightly more natural feel to the custom field. So let's modify our HTML and CSS a bit.

<div class="file-input">
  <input type="file" id="file" class="file">
  <label for="file">
    Select file
    <p class="file-name"></p>
  </label>
</div>
Enter fullscreen mode Exit fullscreen mode
.file-name {
  position: absolute;
  bottom: -35px;
  left: 10px;
  font-size: 0.85rem;
  color: #555;
}
Enter fullscreen mode Exit fullscreen mode

Finally, we would add an event listener to the file input and reflect the name and size of the file below the label.

const file = document.querySelector('#file');
file.addEventListener('change', (e) => {
  // Get the selected file
  const [file] = e.target.files;
  // Get the file name and size
  const { name: fileName, size } = file;
  // Convert size in bytes to kilo bytes
  const fileSize = (size / 1000).toFixed(2);
  // Set the text content
  const fileNameAndSize = `${fileName} - ${fileSize}KB`;
  document.querySelector('.file-name').textContent = fileNameAndSize;
});
Enter fullscreen mode Exit fullscreen mode

Here's how everything looks.

And that's it for the file input. You could decide to style this however you want to get the behavior you want, it's up to you. Happy styling!😁😁

Top comments (6)

Collapse
 
louislow profile image
Louis Low

This also can be replicated by using the Yogurt Framework.

Method #1: ...with inline styling in .html.

<y class="relative">
  <y class="absolute">
    <input class="opacity-0"
           type="file" 
           id="file">
    <label class="flex justify-center items-center w-48 h-12 text-white font-semibold bg-gradient start-pink-500 start-10 stop-indigo-500 stop-90 angle-45 transition duration-300 ease-in-out transform hover:-translate-y-1 rounded-full shadow cursor-pointer"
           for="file">
      Select file
    </label>
  </y>
</y>
Enter fullscreen mode Exit fullscreen mode

Method #2: ... with a separate .scss file styling.

<!-- index.html -->
<y class="file-input">
  <input type="file" 
         id="file">
  <label for="file">
    Select file
  </label>
</y>
Enter fullscreen mode Exit fullscreen mode
// @file: style.scss
.file-input {
  @extend
    // layout
    .relative;

  input {
    @extend
      // layout
      .absolute,
      // effects
      .opacity;
  }

  label {
    @extend
      // flex
      .flex, .justify-center, .items-center,
      // spacing
      .w-48, .h-12, 
      // typography
      .text-white, .font-semibold,
      // backgrounds
      .bg-gradient, .start-pink-500, .start-10, .stop-indigo-500, .stop-90, .angle-45,
      // transistions
      .transition, .duration-300, .ease-in-out,
      // transforms
      .transform .hover\:-translate-y-1,
      // borders
      .rounded-full, 
      // effects
      .shadow, 
      // interactivity
      .cursor-pointer;
  }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
shmshd profile image
Shamshid

Your framework looks like a mini TailwindCSS.

Collapse
 
jonascrft profile image
jonas.C

Tailwind lovers see tailwind everywhere. ^^

Collapse
 
vikasjk profile image
Vikas-jk • Edited on

You can also simply use bootstrap (with Javascript to upload file)

      <div class="col-lg-6 col-sm-6 col-12">

        <div class="input-group">
            <label class="input-group-btn">
                <span class="btn btn-primary">
                    Browse&hellip; <input type="file" style="display: none;" id="file" multiple>
                </span>
            </label>
            <input type="text" class="form-control" id="inputBox" readonly>
        </div>

    </div>
Enter fullscreen mode Exit fullscreen mode

Source: Styling Input type="file" button using CSS & Bootstrap

Collapse
 
tundeondotnet profile image
Akeem Aweda

Good job bro!

Collapse
 
pavelloz profile image
Paweł Kowalski

For those who need more features and some integrations: uppy.io :-)

Classic DEV Post from 2020:

js visualized

🚀⚙️ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! 🥳

Happy coding!