1057

How do you style an input type="file" button?

<input type="file" />
BSMP
  • 4,596
  • 8
  • 33
  • 44
Shivanand
  • 11,099
  • 5
  • 24
  • 31
  • I will add my own answer to do it the way I did...but here is an example based on bootstrap which might help.. http://geniuscarrier.com/how-to-style-a-html-file-upload-button-in-pure-css/ – Vishnu Narang Apr 07 '17 at 23:37
  • The problem with this element, seems to be that does not take styling like other elements similar to them. Like `input type="submit">`. I applied the same styling to both input types, and this is what I got: https://i.imgur.com/7MI1Poh.jpg – carloswm85 Jul 09 '21 at 20:44
  • Well, what worked for me was just placing a div above the Input element and style the div as you want. Then make Input opacity to 0 and make it the same size has the div. – Ricardo Figueiredo Jan 07 '22 at 01:51

48 Answers48

1530

You don't need JavaScript for this! Here is a cross-browser solution:

See this example! - It works in Chrome/FF/IE - (IE10/9/8/7)

The best approach would be to have a custom label element with a for attribute attached to a hidden file input element. (The label's for attribute must match the file element's id in order for this to work).

<label for="file-upload" class="custom-file-upload">
    Custom Upload
</label>
<input id="file-upload" type="file"/>

As an alternative, you could also just wrap the file input element with a label directly: (example)

<label class="custom-file-upload">
    <input type="file"/>
    Custom Upload
</label>

In terms of styling, just hide1 the input element using the attribute selector.

input[type="file"] {
    display: none;
}

Then all you need to do is style the custom label element. (example).

.custom-file-upload {
    border: 1px solid #ccc;
    display: inline-block;
    padding: 6px 12px;
    cursor: pointer;
}

1 - It's worth noting that if you hide the element using display: none, it won't work in IE8 and below. Also be aware of the fact that jQuery validate doesn't validate hidden fields by default. If either of those things are an issue for you, here are two different methods to hide the input (1, 2) that work in these circumstances.

Community
  • 1
  • 1
Josh Crozier
  • 233,099
  • 56
  • 391
  • 304
  • 81
    I do have a question with this one though, when selecting a file how would we go about then displaying the file name ? – Richlewis Jan 20 '15 at 12:17
  • 1
    @Richlewis Any luck with displaying the file name? I´d like to display the image as well... – Asle G Feb 10 '15 at 09:17
  • @AsleG yes it can be achieved with JavaScript/jQuery – Richlewis Feb 10 '15 at 09:19
  • Really marvellous! I use it without "display:none;"
    to just add some more padding to the (rather thin by default) strip. IE will revert to ugly "deep" textfield for the filename when styling input[type=file] directly (afaik, it only accepts 'width')
    – apurkrt Mar 22 '15 at 13:18
  • 27
    How to display the name of selected file if `display: none` is set for `input[type=file]`? – Sarthak Singhal Aug 07 '15 at 09:17
  • 64
    Great solution, but you actually do need javascript. If you want to display the file name, as other people have been asking, you need to add a span between the label and the hidden input: . Then update the span on the change event: $('#file-upload').bind('change', function() { var fileName = ''; fileName = $(this).val(); $('#file-selected').html(fileName); }) – Sam Apr 06 '16 at 19:05
  • 1
    It should also be noted that when doing display:none that capture="camera" will not behave properly. This is the method we implemented to style, but have run into the capture issue when working with iOS devices. – Dustin Jensen Aug 19 '16 at 21:36
  • 23
    You should use `position: absolute; left: -99999rem` instead of `display: none` for accessibility reasons. Most of the time, screen readers will not read elements if they are hidden using the `display: none` method. – Capsule Aug 30 '16 at 01:29
  • @Capsule Yeah, I linked to two alternative examples at the bottom of the post that don't use `display: none`. – Josh Crozier Aug 30 '16 at 01:37
  • 1
    I think it's still important to specify it's not only for IE8 and jQuery validate :-) I reckon the absolute position doesn't have any drawback, and imho, that should be the weapon of choice when hiding elements for presentation purposes only. – Capsule Aug 30 '16 at 01:54
  • I do not see how this is an answer if you cannot read the filename of the selected file without scripting. – Anders Lindén Nov 08 '16 at 10:26
  • None of provided samples/codes work for older IE's (at least not worked in IE-7 as i tested it in a real environment). I found this post http://stackoverflow.com/a/18164555/2803565 which works in IE7. – S.Serpooshan Dec 24 '16 at 09:44
  • This is actually how github does it. You can see it in action when you try to upload profile picture. + 1 – Minjun Yu Jun 27 '17 at 17:47
  • 1
    In complement to @Sam answer, I was receiving a C:/fakepath/filename/... and decide just to show the user that his has one file prepare for upload with this javascript: $('#file-upload').bind('change', function() { var fileName = ''; fileName = '1 file selected'; $('#file-selected').html(fileName); }) – Luigi Lopez Jul 05 '17 at 05:47
  • 1
    In a CSS only challenge this would be a nice solution. But we live in a Javascript world, and displaying the file name is REALLY important for the UX. So this does still need JS to work properly. – Marine Le Borgne Sep 27 '17 at 15:16
  • 1
    that works with a click on the label, but tabbing to it and pressing enter does not work... – Damien Sep 29 '17 at 19:55
  • 2
    At least in Chrome and FF, you can drag&drop files on the input element. With this solution, you loose that ability which is annoying. Has anyone encountered that problem and found a solution ? – Gilles jr Bisson Mar 06 '18 at 05:10
  • 3
    To add to @Sam's comment, to avoid the "fakepath" problem, change the last line to ' $('#file-selected').html(fileName.replace(/^.*\\/, ""));' – Steve Smith Apr 05 '18 at 11:42
  • 1
    This breaks drag-n-drop support (same as any other solution that hides the input field). – wonder.mice Aug 24 '18 at 14:25
  • 54
    I'm very surprised to find no-one seems to have considered keyboard accessibility. `label` elements are not keyboard accessible, unlike `button`s and `input`s. Adding `tabindex` is not a solution because the `label` will still not be actioned when it has focus and the user presses enter. I solved this by *visually* hiding the input, so it can still be focussed, and then using `:focus-within` on the `label` parent: http://jsbin.com/fokexoc/2/edit?html,css,output – Oliver Joseph Ash Sep 25 '18 at 10:44
  • 4
    You don't have to use jQuery just add the span like @Sam said and add `onchange="showname()"` to your **input type file**. Make sure you add the function to get the filename: `function showname() { var name = document.getElementById('datei'); document.getElementById("file-selected").innerHTML = name.files.item(0).name; };`. This came to my mind while reading here: https://stackoverflow.com/questions/2189615/how-to-get-file-name-when-user-select-a-file-via-input-type-file – phrogg Jan 11 '19 at 10:22
  • 1
    Another way to hide the `` element is by using `visibility: hidden` and by changing the position to `position: absolute`. – Lloyd Dominic May 07 '19 at 09:12
  • 2
    @OliverJosephAsh: As somebody who's fought with a lot of PMs about the importance of a11y, I'm afraid I'm not surprised at all. – Michael Scheper May 22 '19 at 16:10
  • 2
    @Capsule another way to hide things while still being accessible is `opacity: 0` – Marc Sloth Eastman Jun 17 '19 at 15:30
  • @MarcSlothEastman yes, but it's not that simple, see https://zellwk.com/blog/hide-content-accessibly/ – Capsule Jun 18 '19 at 00:52
  • 1
    The downside is that this input cannot be navigated to with TAB, and if somehow I want the upload button to be disabled under certain business condition then that would be hard. – Nam Le May 05 '21 at 11:03
  • I tried a much more complicated solution then realised @OliverJosephAsh's approach was much simpler and more effective (I just misunderstood it the first time I read it). I used more or less the same styling as the zellwk.com blog: `pointer-events: none; filter: opacity(0); position: absolute;`. Oliver's solution still works with position absolute (at least on Chrome - I'm not ready to test on multiple browsers yet.) – s6mike Dec 12 '22 at 01:32
302

Styling file inputs are notoriously difficult, as most browsers will not change the appearance from either CSS or javascript.

Even the size of the input will not respond to the likes of:

<input type="file" style="width:200px">

Instead, you will need to use the size attribute:

<input type="file" size="60" />

For any styling more sophisticated than that (e.g. changing the look of the browse button) you will need to look at the tricksy approach of overlaying a styled button and input box on top of the native file input. The article already mentioned by rm at www.quirksmode.org/dom/inputfile.html is the best one I've seen.

UPDATE

Although it's difficult to style an <input> tag directly, this is easily possible with the help of a <label> tag. See answer below from @JoshCrozier: https://stackoverflow.com/a/25825731/10128619

cbdeveloper
  • 27,898
  • 37
  • 155
  • 336
Jonathan Moffatt
  • 13,309
  • 8
  • 51
  • 49
  • 7
    Just found a jquery solution based on this script here: http://blog.vworld.at/2008/08/21/styling-an-input-typefile-using-jquery/ – mtness Feb 03 '11 at 16:23
  • 1
    @TLK Ryan's answer won't work in IE when trying to do iframe uploads. It gives you an access denied error. For normal uploads, I agree it is the easiest though! – frostymarvelous Dec 30 '13 at 13:54
  • 3
    A much simpler solution than quirksmode's is explained [here](http://stackoverflow.com/a/21842275/1256925). Just putting that link here, since this answer is basically a link-only answer anyway. – Joeytje50 May 07 '14 at 16:30
  • 13
    For anyone interested in a modern approach, i'd suggest looking at [**this answer**](http://stackoverflow.com/questions/572768/styling-an-input-type-file-button/25825731#25825731). It doesn't require JavaScript like some of the other answers either. – Josh Crozier Sep 13 '14 at 17:43
  • 3
    @JoshCrozier posted an insanely much better solution. Even beats fake-mouseclicking solutions :) – Lodewijk Sep 18 '14 at 00:16
  • i guess there are good security reasons for making it a standardized always recognizable way for the browser to leave its sandbox – tObi Jul 10 '15 at 14:53
218

follow these steps then you can create custom styles for your file upload form:

  1. this is the simple HTML form(please read the HTML comments I have written here below)

    <form action="#type your action here" method="POST" enctype="multipart/form-data">
      <div id="yourBtn" style="height: 50px; width: 100px;border: 1px dashed #BBB; cursor:pointer;" onclick="getFile()">Click to upload!</div>
      <!-- this is your file input tag, so i hide it!-->
      <div style='height: 0px;width:0px; overflow:hidden;'><input id="upfile" type="file" value="upload"/></div>
      <!-- here you can have file submit button or you can write a simple script to upload the file automatically-->
      <input type="submit" value='submit' >
    </form>
    
  2. then use this simple script to pass the click event to file input tag.

    function getFile(){
         document.getElementById("upfile").click();
    }
    

    Now you can use any type of styling without worrying about how to change default styles.

I know this very well because I have been trying to change the default styles for a month and a half. believe me, it's very hard because different browsers have different upload input tag. So use this one to build your custom file upload forms. Here is the full AUTOMATED UPLOAD code.

function getFile() {
  document.getElementById("upfile").click();
}

function sub(obj) {
  var file = obj.value;
  var fileName = file.split("\\");
  document.getElementById("yourBtn").innerHTML = fileName[fileName.length - 1];
  document.myForm.submit();
  event.preventDefault();
}
#yourBtn {
  position: relative;
  top: 150px;
  font-family: calibri;
  width: 150px;
  padding: 10px;
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border: 1px dashed #BBB;
  text-align: center;
  background-color: #DDD;
  cursor: pointer;
}
<form action="#type your action here" method="POST" enctype="multipart/form-data" name="myForm">
  <div id="yourBtn" onclick="getFile()">click to upload a file</div>
  <!-- this is your file input tag, so i hide it!-->
  <!-- i used the onchange event to fire the form submission-->
  <div style='height: 0px;width: 0px; overflow:hidden;'><input id="upfile" type="file" value="upload" onchange="sub(this)" /></div>
  <!-- here you can have file submit button or you can write a simple script to upload the file automatically-->
  <!-- <input type="submit" value='submit' > -->
</form>
H. Pauwelyn
  • 13,575
  • 26
  • 81
  • 144
teshguru
  • 3,505
  • 1
  • 18
  • 6
  • 6
    @user1053263 -> Thanks for the recommendation.. here i used a very simple java script, no need to use frameworks like Jquery or PrototypeJS. – teshguru Mar 15 '12 at 06:09
  • 7
    I'm having troubles submitting the form in IE9. I'm getting an 'Access is Denied' error which trying to submit the form via javascript. If i click the submit button via the UI, it works. Is there a work around for this? – Kevin Mar 23 '12 at 19:29
  • 1
    @kevin -> Please try event.preventDefault() after document.myForm.submit() , i made the change to the above code. – teshguru Mar 24 '12 at 04:21
  • 1
    Works well in Chrome, Firefox, Safari & Opera - but not in IE9. In IE9 I get the same 'Access is Denied' error as @Kevin - and sometimes just a silent fail with no error. – daveywc Jul 04 '12 at 04:54
  • event.preventDefault() gives the following error in IE: Object doesn't support property or method 'preventDefault'. – daveywc Jul 04 '12 at 05:06
  • Two issues with this: This was missing --name="upfile"-- And second where is "event" defined ? – haknick Dec 13 '12 at 23:11
  • 10
    In IE10 (and possibly IE9, etc.) you will get "Access is Denied" (or no response from jQuery) if you try and automatically submit the form after clicking the file input button through javascript. So this method works for styling the file input button as long as the user is still the one submitting the form. Took me a while to find this and I see others also have the same issue. See this for more info http://stackoverflow.com/a/4335390/21579. – Jeff Widmer Mar 19 '13 at 13:28
  • Works perfectly in IE8 and IE9 and Chrome. Best solution for this problem! – joshkrz Apr 30 '13 at 21:13
  • display:none works fine on the upfile container and its better to put this rule in the header style sheet. @teshguru ty – aelgoa Oct 25 '13 at 07:15
  • Doesn't work with Chrome anymore. It's not allowed to trigger a click event on file-input through javascript – Jay Regal Jul 17 '14 at 10:00
  • Late to the party here, but I cant seem to get this to work with multiple upload buttons. Even changing all the variable so its two separate scripts results in only one of the two working. Any ideas? – Epleroma Aug 18 '15 at 17:23
  • Does this work on mobile devices? I know that the iOS systems are very nazi-like when it comes to file upload. – nu everest Aug 31 '16 at 14:07
  • Shame that this is reliant on JS – gypsydave5 Sep 24 '18 at 09:51
  • For those who want to implement this in React, see [this](https://medium.com/web-dev-survey-from-kyoto/how-to-customize-the-file-upload-button-in-react-b3866a5973d8) article. The code can be accessed directly [here](https://github.com/masakudamatsu/line-height-picker/blob/master/src/components/FontFileUploader.js). You can see a gist on how to implement this in TypeScript [here](https://gist.github.com/nathanpovo/7a546ac0a8f71b2db8e161522c1ba8ea). – somethingRandom Jul 28 '22 at 05:27
  • this way is the best. I tried the 'label hack' way, but it was complicating my dynamic layout ,as the label seems to behave outside of the flow of the page, only taking as much space as the original label – Sharkfin Aug 22 '22 at 11:58
122

::file-selector-button

https://developer.mozilla.org/en-US/docs/Web/CSS/::file-selector-button

This is a new selector that can be used to style the file selector button.

It has full support on recent browser versions.

input[type=file]::file-selector-button {
  border: 2px solid #6c5ce7;
  padding: .2em .4em;
  border-radius: .2em;
  background-color: #a29bfe;
  transition: 1s;
}

input[type=file]::file-selector-button:hover {
  background-color: #81ecec;
  border: 2px solid #00cec9;
}
<form>
  <label for="fileUpload">Upload file</label>
  <input type="file" id="fileUpload">
</form>

Here is another snippet that demonstrates different styling:

.input_container {
  border: 1px solid #e5e5e5;
}

input[type=file]::file-selector-button {
  background-color: #fff;
  color: #000;
  border: 0px;
  border-right: 1px solid #e5e5e5;
  padding: 10px 15px;
  margin-right: 20px;
  transition: .5s;
}

input[type=file]::file-selector-button:hover {
  background-color: #eee;
  border: 0px;
  border-right: 1px solid #e5e5e5;
}
<form>
  <div class="input_container">
    <input type="file" id="fileUpload">
  </div>
</form>

I felt that this answer was needed as most answers here are outdated.


Customize Input Text

If you want to customize the text of the file selector button, here is a snippet:

document.querySelector("#files").onchange = function() {
  const fileName = this.files[0]?.name;
  const label = document.querySelector("label[for=files]");
  label.innerText = fileName ?? "Browse Files";
};
label {
  border: 1px solid #e5e5e5;
  border-radius: 10px;
  padding: 5px 10px;
  font-family: 'Helvetica', sans-serif;
  transition: .5s;
}

label:hover {
  background-color: #eee;
}
<div class="input_container">
  <label for="files" class="btn">Browse Files</label>
  <input id="files" style="display:none;" type="file">
</div>

I preferred to use a vanilla solution for simplicity. View this post if you want a jQuery version of the above snippet.

ADAMJR
  • 1,880
  • 1
  • 14
  • 34
87

All rendering engines automatically generate a button when an <input type="file"> is created. Historically, that button has been completely un-styleable. However, Trident and WebKit have added hooks through pseudo-elements.

Trident

As of IE10, the file input button can be styled using the ::-ms-browse pseudo-element. Basically, any CSS rules that you apply to a regular button can be applied to the pseudo-element. For example:

::-ms-browse {
  background: black;
  color: red;
  padding: 1em;
}
<input type="file">

This displays as follows in IE10 on Windows 8:

This displays as follows in IE10 on Windows 8:

WebKit

WebKit provides a hook for its file input button with the ::-webkit-file-upload-button pseudo-element. Again, pretty much any CSS rule can be applied, therefore the Trident example will work here as well:

::-webkit-file-upload-button {
  background: black;
  color: red;
  padding: 1em;
}
<input type="file">

This displays as follows in Chrome 26 on OS X:

This displays as follows in Chrome 26 on OS X:

Anselm
  • 7,450
  • 3
  • 28
  • 37
79

Hide it with css and use a custom button with $(selector).click() to activate the the browse button. then set an interval to check the value of the file input type. the interval can display the value for the user so the user can see whats getting uploaded. the interval will clear when the form is submitted [EDIT] Sorry i have been very busy was meaning to update this post, here is an example

<form action="uploadScript.php" method="post" enctype="multipart/form-data">
<div>
    <!-- filename to display to the user -->
    <p id="file-name" class="margin-10 bold-10"></p>

    <!-- Hide this from the users view with css display:none; -->
    <input class="display-none" id="file-type" type="file" size="4" name="file"/>

    <!-- Style this button with type image or css whatever you wish -->
    <input id="browse-click" type="button" class="button" value="Browse for files"/>

    <!-- submit button -->
    <input type="submit" class="button" value="Change"/>
</div>

$(window).load(function () {
    var intervalFunc = function () {
        $('#file-name').html($('#file-type').val());
    };
    $('#browse-click').on('click', function () { // use .live() for older versions of jQuery
        $('#file-type').click();
        setInterval(intervalFunc, 1);
        return false;
    });
});
Ryan
  • 1,119
  • 7
  • 10
  • 8
    Note that if you use this way it will break in internet explorer because its an security exception.. – Rejinderi Jan 30 '12 at 15:17
  • 1
    thanks the tip. When i use IE it usually has a separate layout to everything else. HATE IE. but i simplify everything in IE. – Ryan Jan 31 '12 at 08:54
  • 1
    With FF20, $('#file-type').click() doesn't seem to bring up the "Choose file" dialg- in fact nothing happens. Any ideas? – andig Mar 10 '13 at 11:02
  • 2
    Try using the trigger method in jquery. Also .live changed to .on() in the new jquery – Ryan Mar 18 '13 at 08:34
  • 1
    once you've set that interval at what point can I clear it? else it will be constantly firing – Dave Haigh Jul 30 '13 at 16:02
  • @dave just make the set Interval a variable eg var interval = setInterval(intervalFunc, 1); and when ever you want to stop it use the clearInterval javascript function. Yes it will constantly fire but its to keep the filename up to date if a user keeps changing the file they have selected. So logically it would make sense to clear the interval once a user has clicked upload or finished using the button – Ryan Jul 31 '13 at 08:02
  • @Ryan yep that makes sense. But how do I detect when someone has clicked upload? – Dave Haigh Jul 31 '13 at 08:29
  • @Rejinderi I havent been able to break it in IE. does it break in specific versions of IE and what breakage should I see? – Dave Haigh Jul 31 '13 at 11:56
  • @Dave place either an id on your form and use $('#formid').submit(function(){/*clear interval here*/}); or place an id on the submit button and use $('#submitbutton').click(function(){/*clear interval here*/}); – Ryan Jul 31 '13 at 13:38
  • Where is the "C:\fakepath\" coming from and how do I get rid of it? – Will Andrew Nov 11 '13 at 11:16
  • @WillAndrew: you can get the file name only, without the `"C:\fakepath\"`, by handling it in JavaScript (get the upload file name instead of the value of the upload file). Let's say: `document.getElementById('showUploadFileName').value = document.getElementById('uploadFileInputFieldId').files[0].name;` – nyedidikeke Jun 23 '17 at 07:06
74

$('.new_Btn').click(function() {
  $('#html_btn').click();
});
.new_Btn {
  // your css propterties
}

#html_btn {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="new_Btn">SelectPicture</div><br>
<input id="html_btn" type='file' /><br>

You can reach your goals too without jQuery with normal JavaScript.

Now the newBtn is linkes with the html_btn and you can style your new btn like you want :D

Krishna Jangid
  • 4,961
  • 5
  • 27
  • 33
Wykk
  • 812
  • 6
  • 12
  • 1
    Just curious, does it work in every browser of new generation such as Firefox, IE, Opera, Safari, Chrome, etc? – Wh1T3h4Ck5 Oct 04 '12 at 23:17
  • This is the simplest solution for me! A least in IE 9, Chrome 23 and FF 16 with jQuery 1.7.2, so with updated versions it should work. – Dani bISHOP Nov 14 '12 at 11:38
  • Does anyone know how to change the .new_Btn in case the user has chosen an image. Now it just shows the same class. Anyone know how to track that? Thanks – Ando Feb 04 '13 at 09:38
  • 2
    @MehdiKaramosly it works even on IE 6 - but that is true **only up to jQuery 1.x** , jQuery 2.x+ does not support old IEs – jave.web May 21 '14 at 15:01
  • 1
    @Ando via Javascript/jQuery => the value of the file input is empty or contains local file path => use onchange event and test for val() :) see http://jsfiddle.net/ZrBPF/ – jave.web May 21 '14 at 15:16
  • `document.getElementById('id_inputButtonReal').files.item(0).name` gives name of file uploaded. Future ref -- https://stackoverflow.com/a/43209669/3842788 – Aseem Apr 28 '19 at 13:30
43

If you are using Bootstrap 3, this worked for me:

See https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/

.btn-file {
  position: relative;
  overflow: hidden;
}
.btn-file input[type=file] {
  position: absolute;
  top: 0;
  right: 0;
  min-width: 100%;
  min-height: 100%;
  font-size: 100px;
  text-align: right;
  filter: alpha(opacity=0);
  opacity: 0;
  outline: none;
  background: white;
  cursor: inherit;
  display: block;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />

<span class="btn btn-primary btn-file">
    Browse...<input type="file">
</span>

Which produces the following file input button:

Example button

Seriously, check out https://www.abeautifulsite.net/posts/whipping-file-inputs-into-shape-with-bootstrap-3/

JDawg
  • 8,560
  • 4
  • 25
  • 29
34

Working example here with native Drag and drop support : https://jsfiddle.net/j40xvkb3/

When styling a file input, you shouldn't break any of native interaction the input provides.

The display: none approach breaks the native drag and drop support.

To not break anything, you should use the opacity: 0 approach for the input, and position it using relative / absolute pattern in a wrapper.

Using this technique, you can easily style a click / drop zone for the user, and add custom class in javascript on dragenter event to update styles and give user a feedback to let him see that he can drop a file.

HTML :

<label for="test">
  <div>Click or drop something here</div>
  <input type="file" id="test">
</label>

CSS :

input[type="file"] {
  position: absolute;
  left: 0;
  opacity: 0;
  top: 0;
  bottom: 0;
  width: 100%;
}

div {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #ccc;
  border: 3px dotted #bebebe;
  border-radius: 10px;
}

label {
  display: inline-block;
  position: relative;
  height: 100px;
  width: 400px;
}

Here is a working example (with additional JS to handle dragover event and dropped files).

https://jsfiddle.net/j40xvkb3/

Hope this helped !

kevcha
  • 1,002
  • 9
  • 15
  • thanks for the post , how does this work if multiple="multiple" attribute is added, i dragged 2 images yet saw the path for only the 1st one – PirateApp Dec 13 '17 at 17:19
  • You have missed code here. There is more on the fiddle. What library? – ctrl-alt-delor Dec 05 '18 at 09:37
  • There is just some javascript on the fiddle with jQuery to show files that has been dropped. That's all – kevcha Dec 10 '18 at 17:54
  • Having implemented this solution and tested it further, it doesn't seem to work either in Edge. – ChrisA Apr 22 '19 at 15:24
  • I'll try to get a computer with edge to try it out – kevcha Apr 24 '19 at 09:31
  • NEVER position your input[type="file"] as position: absolute; This will cause such strange jumping / overflow/ scroll bugs that you will have no idea where they came from – Tom Aug 29 '19 at 12:47
  • @Tom I've never had this kind of issue with the technique – kevcha Aug 30 '19 at 12:14
  • 1
    Ah ok, I missed the wrapper with position relative in your answer - My bad. If the input is below the screen dimensions, the browser tries to scroll to it and in doing so, moves the scroll container up the page. Here is a demonstration: https://stackblitz.com/edit/input-file-overflow?file=style.css (just not exactly demonstrating how position absolute is the cause of the behaviour) – Tom Aug 31 '19 at 05:23
  • The best solution presented here so far. Not only you get a customized upload zone, but it also preserves _drag and drop_ functionality. Thank you! – informatik01 Mar 25 '20 at 00:12
27

I am able to do it with pure CSS using below code. I have used bootstrap and font-awesome.

<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet" />

<label class="btn btn-default btn-sm center-block btn-file">
  <i class="fa fa-upload fa-2x" aria-hidden="true"></i>
  <input type="file" style="display: none;">
</label>
Karthik
  • 1,447
  • 1
  • 18
  • 26
26

ONLY CSS

Use this very simple and EASY

.choose::-webkit-file-upload-button {
  color: white;
  display: inline-block;
  background: #1CB6E0;
  border: none;
  padding: 7px 15px;
  font-weight: 700;
  border-radius: 3px;
  white-space: nowrap;
  cursor: pointer;
  font-size: 10pt;
}
<label>Attach your screenshort</label>
<input type="file" multiple class="choose">
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Balvant Ahir
  • 610
  • 1
  • 9
  • 16
  • 2
    simple but not supported everywhere – Owow Aug 12 '20 at 09:12
  • 1
    That's a lot better than the other solutions which do not display the name of selected file(s). But how to change the text "Choose Files". A person really has to wonder about the competence of the people behind HTML/CSS standards, who comes up with the stuff? So poorly done. – Gerry Oct 05 '20 at 16:39
  • I only add that firefox has it own similar class ::file-selector-button – Robert Feb 06 '21 at 02:25
24
 <label>
    <input type="file" />
 </label>

You can wrap your input type="file" inside of a label for the input. Style the label however you'd like and hide the input with display: none;

JGuo
  • 384
  • 2
  • 7
  • An alternative might be https://gist.github.com/barneycarroll/5244258 or http://jsfiddle.net/4cwpLvae/ (works in IE11) – surfmuggle Sep 21 '17 at 12:01
19

This approach gives you the whole flexibility! ES6 / VanillaJS!

html:

<input type="file" style="display:none;"></input>
<button>Upload file</button>

javascript:

document.querySelector('button').addEventListener('click', () => {
  document.querySelector('input[type="file"]').click();
});

This hides the input-file button, but under the hood clicks it from another normal button, that you can obviously style like any other button. This is the only solution with no downside apart from a useless DOM-node. Thanks to display:none;, the input-button does not reserve any visible space in the DOM.

(I don't know anymore to whom to give props for this. But I got that idea from somewhere here on Stackoverflow.)

codepleb
  • 10,086
  • 14
  • 69
  • 111
15

Put upload file button over your nice button or element and hide it.

Very simple and will work on any browser

<div class="upload-wrap">
    <button type="button" class="nice-button">upload_file</button>
    <input type="file" name="file" class="upload-btn">
</div>

Styles

.upload-wrap {
    position: relative;
}

.upload-btn {
    position: absolute;
    left: 0;
    opacity: 0;
}
Tigran Babajanyan
  • 1,967
  • 1
  • 22
  • 41
14

Here is a solution which doesn't really style the <input type="file" /> element but instead uses a <input type="file" /> element on top of other elements (which can be styled). The <input type="file" /> element is not really visible hence, the overall illusion is of a nicely styled file upload control.

I came across this problem recently and despite the plethora of answers on Stack Overflow, none really seemed to fit the bill. In the end, I ended up customizing this so as to have a simple and an elegant solution.

I have also tested this on Firefox, IE (11, 10 & 9), Chrome and Opera, iPad and a few android devices.

Here's the JSFiddle link -> http://jsfiddle.net/umhva747/

$('input[type=file]').change(function(e) {
    $in = $(this);
    $in.next().html($in.val());
    
});

$('.uploadButton').click(function() {
    var fileName = $("#fileUpload").val();
    if (fileName) {
        alert(fileName + " can be uploaded.");
    }
    else {
        alert("Please select a file to upload");
    }
});
body {
    background-color:Black;
}

div.upload {
    background-color:#fff;
    border: 1px solid #ddd;
    border-radius:5px;
    display:inline-block;
    height: 30px;
    padding:3px 40px 3px 3px;
    position:relative;
    width: auto;
}

div.upload:hover {
    opacity:0.95;
}

div.upload input[type="file"] {
    display: input-block;
    width: 100%;
    height: 30px;
    opacity: 0;
    cursor:pointer;
    position:absolute;
    left:0;
}
.uploadButton {
    background-color: #425F9C;
    border: none;
    border-radius: 3px;
    color: #FFF;
    cursor:pointer;
    display: inline-block;
    height: 30px;
    margin-right:15px;
    width: auto;
    padding:0 20px;
    box-sizing: content-box;
}

.fileName {
    font-family: Arial;
    font-size:14px;
}

.upload + .uploadButton {
    height:38px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<form action="" method="post" enctype="multipart/form-data">
    <div class="upload">
        <input type="button" class="uploadButton" value="Browse" />
        <input type="file" name="upload" accept="image/*" id="fileUpload" />
        <span class="fileName">Select file..</span>
    </div>
    <input type="button" class="uploadButton" value="Upload File" />
</form>

Hope this helps!!!

Satwik Nadkarny
  • 5,086
  • 2
  • 23
  • 41
13

This is simple with jquery. To give a code example of Ryan's suggestion with a slight modification.

Basic html:

<div id="image_icon"></div>
<div id="filename"></div>
<input id="the_real_file_input" name="foobar" type="file">

Be sure to set the styling on the input when you're ready: opacity: 0 You can't set display: none because it needs to be clickable. But you can position it under the "new" button or tuck in under something else with z-index if you prefer.

Setup some jquery to click the real input when you click the image.

$('#image_icon').click(function() {
    $('#the_real_file_input').click();
});

Now your button is working. Just cut and paste the value when changed.

$('input[type=file]').bind('change', function() {
    var str = "";
    str = $(this).val();
    $("#filename").text(str);
}).change();

Tah dah! You may need to parse the val() to something more meaningful but you should be all set.

Jun Yu
  • 375
  • 1
  • 5
  • 21
TLK
  • 1,770
  • 1
  • 17
  • 32
  • 1
    this will fail with FF11 - reason: since you cannot precisely influence size of input field (only by using html size) and button (you can set height using css), if your visible input field is larger than original FF provides us with, you are left with a very big blind area - user standpoint: in most cases he'll complain that upload does not work, when clicked – Jeffz Mar 31 '12 at 23:10
  • 2
    Good idea but this will not work on IE. $('#the_real_file_input').click() will trigger open dialog but file will not be selected into a form and upload will fail. – Tomas Aug 21 '12 at 12:04
12

Here is a PURE CSS, Javascript-free, Bootstrap-free, 100% cross-browser solution! Just cut-and-paste one block of styles, then test your file upload control.

This solution does NOT attempt to hide then recreate the original HTML element like the other posts here do. It uses plain CSS without any circus tricks or third party tools to style the original file upload form control for all the major browsers. You do not need to even change your HTML code! Just cut-and-paste the code below into your web page to test it...

<style>
/* Note: This CSS will style all instances of 
   <input type=file /> controls in your website. */
input[type="file"],
input[type="file"]:visited,
input[type="file"]:hover,
input[type="file"]:focus,
input[type="file"]:active {
    margin:0;
    padding: 0em 0em;/* fallback: older browsers like IE 1-8 need "em" */
    padding: 0rem 0rem;/* older browsers dont know what "rem" is */
    overflow: hidden; /* long file names overflow so just hide the end */
    background: #fff;
    border-radius: .2em;
    border-radius: .2rem;
    outline: none;
    border: 2px solid #bbb;
    cursor: pointer;
    -webkit-appearance: textfield;
    -moz-appearance: textfield;
}

input[type="file"]:hover {
    background: #f9f9ff; /* Optional rollover color: I am using a light blue to indicate an interaction */
    border: 2px solid #999;
}

input[type="file"]:visited,
input[type="file"]:focus,
input[type="file"]:active {
    background: #fff; /* Default back to white when focused. */
    border: 2px solid #999;
}

/* Note: These "disabled" selectors blow up in IE so have to be separated from the same styles above. */
input[type="file"]:disabled {
    margin: 0;
    padding: 0em 0em;
    padding: 0rem 0rem;
    overflow: hidden; /* long file names overflow so just hide the end */
    background: #ddd;
    border-radius: .2em;
    border-radius: .2rem;
    outline: none;
    border: 2px solid #bbb;
    cursor: pointer;
    -webkit-appearance: textfield;
    -moz-appearance: textfield;
}

input[type="file"]:disabled:hover {
    background: #ddd; /* disabled-readonly buttons should be grey */
    border: 2px solid #999;
}

input[type="file"]:disabled:visited,
input[type="file"]:disabled:focus,
input[type="file"]:disabled:active {
    background: #ddd; /* disabled-readonly buttons should be grey */
    border: 2px solid #999;
}

/* IE UPLOAD BUTTON STYLE: This attempts to alter the file upload button style in IE.  Keep in mind IE gives you limited design control but at least you can customize its upload button.*/
::-ms-browse { /* IE */
    display: inline-block;
    margin: 0;
    padding: .2em .5em;
    padding: .2rem .5rem;
    text-align: center;
    outline: none;
    border: none;
    background: #fff;
    white-space: nowrap;
    cursor: pointer;
}
/* FIREFOX UPLOAD BUTTON STYLE */
::file-selector-button {/* firefox */
    display: inline-block;
    margin: 0rem 1rem 0rem 0rem;
    padding: .18em .5em;
    padding: .18rem .5rem;
    -webkit-appearance: button;
    text-align: center;
    border-radius: .1rem 0rem 0rem .1rem;
    outline: none;
    border: none;
    border-right: 2px solid #bbb;
    background: #eee;
    white-space: nowrap;
    cursor: pointer;
}
/* CHROME AND EDGE UPLOAD BUTTON STYLE */
::-webkit-file-upload-button { /* chrome and edge */
    display: inline-block;
    margin: 0rem 1rem 0rem 0rem;
    padding: .19em .5em;
    padding: .19rem .5rem;
    -webkit-appearance: button;
    text-align: center;
    border-radius: .1rem 0rem 0rem .1rem;
    outline: none;
    border: none;
    border-right: 2px solid #bbb;
    background: #eee;
    white-space: nowrap;
    cursor: pointer;
}
</style>

<input type="file" id="fileupload" name="fileupload" 
value="" tabindex="0" enctype="multipart/form-data" 
accept="image/*" autocomplete="off" multiple="multiple" 
aria-multiselectable="true" title="Multiple File Upload" 
aria-label="Multiple File Upload" />

<br /><br />

<input disabled="disabled" type="file" id="fileupload" 
name="fileupload" value="" tabindex="0" 
enctype="multipart/form-data" accept="image/*" 
autocomplete="off" multiple="multiple" 
aria-multiselectable="true" title="Disabled Multiple File Upload" 
aria-label="Disabled Multiple File Upload" />

This is what the file upload control looks like in Firefox, Chrome, and Edge using the CSS below. This is a very simple clean design. You can change it to look any way you like:

enter image description here

Internet Explorer gives you limited design control, but at least you can manipulate the control using CSS enough to change a few things, including rounded borders and colors:

enter image description here

The advantages to my solution are:

  1. You stick with simple CSS to style the original HTML input control
  2. You can see one or more file names in the file input textbox
  3. Screen readers and ARIA-friendly devices can interact normally with your file upload control
  4. You can set tabindex on your HTML element so its part of the tab order
  5. Because you are using plain HTML and CSS, your file input button works perfectly in old and new browsers
  6. ZERO JavaScript required!
  7. Runs and loads lighting fast in even the oldest of browsers
  8. Because your are not using "display:none" to hide the control, its file block stream data is never disabled from reaching the server in any old or new browser version known

You do not need goofy JavaScript tricks, Bootstrap, or to try and hide/recreate your file input control. That just destroys usability for everyone online. Styling the original HTML control means your file upload control is guaranteed to work well in 25 years worth of web browsers, old and new.

This is why you cannot trust all these scripted hacks here that erase, rewrite, or destroy HTML just to try and recreate some visual experience. That shows that you do not understand how HTML is used or why its been around for 30 years practically unchanged. You should never try and rewrite HTML's native form control functionality. Why? There is more to using natural HTML in websites than just manipulation of markup for some forced visual experience. The trade-offs of limited visual design in these replaced HTML elements was designed that way for a reason.

My advice: Stay with simple HTML and CSS solutions and you will have ZERO problems as a web developer.

Stokely
  • 12,444
  • 2
  • 35
  • 23
  • 1
    This is the real deal! Thanks a lot! (for others: the button text cannot be changed directly or using :after and :before on the input element, it needs a separate element with `pointer-events: none;` on top of the button. – Barney Szabolcs Mar 26 '21 at 22:48
  • This needs to be adjusted for dark modes. All the backgrounds are set to white here. Otherwise it's good, just a bit of ctrl+h – Patafikss Jul 08 '22 at 17:08
  • @Patafikss yes good point. My solution is more of a default reset sheet applied to all browsers, old and new. If you want a dark mode version, I would set "prefers-color-scheme" media queries with dark versions and style not only my input, but have dark versions of all form fields. – Stokely Jul 12 '22 at 01:36
8
<input type="file" name="media" style="display-none" onchange="document.media.submit()">

I would normally use simple javascript to customize the file input tag.A hidden input field,on click of button,javascript call the hidden field,simple solution with out any css or bunch of jquery.

<button id="file" onclick="$('#file').click()">Upload File</button>
user2086641
  • 4,331
  • 13
  • 56
  • 96
  • 1
    you can't use `click()` method to fire event for input type file. most of the browser doesn't allow for security reason . – Mahi Dec 29 '16 at 09:37
8

VISIBILITY:hidden TRICK

I usually go for the visibility:hidden trick

this is my styled button

<div id="uploadbutton" class="btn btn-success btn-block">Upload</div>

this is the input type=file button. Note the visibility:hidden rule

<input type="file" id="upload" style="visibility:hidden;">

this is the JavaScript bit to glue them together. It works

<script>
 $('#uploadbutton').click(function(){
    $('input[type=file]').click();
 });
 </script>
Community
  • 1
  • 1
Gianluca Ghettini
  • 11,129
  • 19
  • 93
  • 159
  • 1
    you can't use click() method to fire event for input type file. most of the browser doesn't allow for security reason – Mahi Dec 29 '16 at 09:37
  • even using jquery? is that correct? how would you do it instead? – Gianluca Ghettini Dec 29 '16 at 10:42
  • http://stackoverflow.com/questions/210643/in-javascript-can-i-make-a-click-event-fire-programmatically-for-a-file-input – Mahi Dec 29 '16 at 17:04
  • `style="visibility:hidden"` is too long, simply use `hidden`. Also, `click()` does work for any browsers and there is no veryfiable security reason as of now and on any devices it's the legit way and @Gianluca for classic jQuery use `trigger()` – Thielicious Jun 09 '17 at 16:34
  • 1
    This is precisely the solution I was going to add to this! It work and you can display it precisely how you want to. Works with Chrome, will try others. – markthewizard1234 Jul 12 '17 at 10:28
8

Multiple file solution with converted filename

Bootstrap EXAMPLE

HTML:

<div>
  <label class="btn btn-primary search-file-btn">
    <input name="file1" type="file" style="display:None;"> <span>Choose file</span>
  </label>
  <span>No file selected</span>
</div>

<div>
  <label class="btn btn-primary search-file-btn">
    <input name="file2" type="file" style="display:None;"> <span>Choose file</span>
  </label>
  <span>No file selected</span>
</div>

1. JS with jQuery:

$().ready(function($){
    $('.search-file-btn').children("input").bind('change', function() {
    var fileName = '';
    fileName = $(this).val().split("\\").slice(-1)[0];
    $(this).parent().next("span").html(fileName);
  })
});

2. JS without jQuery

Array.prototype.forEach.call(document.getElementsByTagName('input'), function(item) {
  item.addEventListener("change", function() {
    var fileName = '';
    fileName = this.value.split("\\").slice(-1)[0];
    this.parentNode.nextElementSibling.innerHTML = fileName;
  });
});
Community
  • 1
  • 1
ChrisRob
  • 1,515
  • 2
  • 18
  • 30
7

the only way i can think of is to find the button with javascript after it gets rendered and assign a style to it

you might also look at this writeup

roman m
  • 26,012
  • 31
  • 101
  • 133
6

Here we use a span to trigger input of type file and we simply customized that span, so we can add any styling using this way.

Note that we use input tag with visibility:hidden option and trigger it in the span.

.attachFileSpan{
color:#2b6dad;
cursor:pointer;
}
.attachFileSpan:hover{
text-decoration: underline;
}
<h3> Customized input of type file </h3>
<input id="myInput" type="file" style="visibility:hidden"/>

        <span title="attach file" class="attachFileSpan" onclick="document.getElementById('myInput').click()">
        Attach file
        </span>

Reference

Abdallah Okasha
  • 1,879
  • 17
  • 20
5

Here is a solution, that also shows the chosen file name: http://jsfiddle.net/raft9pg0/1/

HTML:

<label for="file-upload" class="custom-file-upload">Chose file</label>
<input id="file-upload" type="file"/>
File: <span id="file-upload-value">-</span>

JS:

$(function() {
    $("input:file[id=file-upload]").change(function() {
        $("#file-upload-value").html( $(this).val() );
    });
});

CSS:

input[type="file"] {
    display: none;
}

.custom-file-upload {
      background: #ddd;
      border: 1px solid #aaa;
      border-top: 1px solid #ccc;
      border-left: 1px solid #ccc;
      -moz-border-radius: 3px;
      -webkit-border-radius: 3px;
      border-radius: 3px;
      color: #444;
      display: inline-block;
      font-size: 11px;
      font-weight: bold;
      text-decoration: none;
      text-shadow: 0 1px rgba(255, 255, 255, .75);
      cursor: pointer;
      margin-bottom: 20px;
      line-height: normal;
      padding: 8px 10px; }
Caleb
  • 343
  • 4
  • 7
5

This is a nice way to do it with material / angular file upload. You could do the same with a bootstrap button.

Note I used <a> instead of <button> this allows the click events to bubble up.

<label>
    <input type="file" (change)="setFile($event)" style="display:none" />

    <a mat-raised-button color="primary">
      <mat-icon>file_upload</mat-icon>
      Upload Document
    </a>

  </label>
Rusty Rob
  • 16,489
  • 8
  • 100
  • 116
  • 1
    This works great in angular 2+. Not sure why it's down voted. If you're using angular this is the simplest solution available. – AndrewWhalan Dec 02 '17 at 11:22
4

Update Nevermind, this doesn't work in IE or it's new brother, FF. Works on every other type of element as expected, but doesn't work on file inputs. A much better way to do this is to just create a file input and a label that links to it. Make the file input display none and boom, it works in IE9+ seamlessly.

Warning: Everything below this is crap!

By using pseudo elements positioned/sized against their container, we can get by with only one input file (no additional markup needed), and style as per usual.

Demo

<input type="file" class="foo">
<style>
    .foo {
        display: block;
        position: relative;
        width: 300px;
        margin: auto;
        cursor: pointer;
        border: 0;
        height: 60px;
        border-radius: 5px;
        outline: 0;
    }
    .foo:hover:after {
        background: #5978f8;
    }
    .foo:after {
        transition: 200ms all ease;
        border-bottom: 3px solid rgba(0,0,0,.2);
        background: #3c5ff4;
        text-shadow: 0 2px 0 rgba(0,0,0,.2);
        color: #fff;
        font-size: 20px;
        text-align: center;
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        display: block;
        content: 'Upload Something';
        line-height: 60px;
        border-radius: 5px;
    }
</style>

Enjoy guys!

Old Update

Turned this into a Stylus mixin. Should be easy enough for one of you cool SCSS cats to convert it.

    file-button(button_width = 150px)
      display block
      position relative
      margin auto
      cursor pointer
      border 0
      height 0
      width 0
      outline none
      &:after
        position absolute
        top 0
        text-align center
        display block
        width button_width
        left -(button_width / 2)

Usage:

<input type="file">

input[type="file"]
    file-button(200px)
Jun Yu
  • 375
  • 1
  • 5
  • 21
corysimmons
  • 7,296
  • 4
  • 57
  • 65
4

Maybe a lot of awnsers. But I like this in pure CSS with fa-buttons:

.divs {
    position: relative;
    display: inline-block;
    background-color: #fcc;
}

.inputs {
    position:absolute;
    left: 0px;
    height: 100%;
    width: 100%;
    opacity: 0;
    background: #00f;
    z-index:999;
}

.icons {
    position:relative;
}
<div class="divs">
<input type='file' id='image' class="inputs">
<i class="fa fa-image fa-2x icons"></i>
</div>

<div class="divs">
<input type='file' id='book' class="inputs">
<i class="fa fa-book fa-5x icons"></i>
</div>
<br><br><br>
<div class="divs">
<input type='file' id='data' class="inputs">
<i class="fa fa-id-card fa-3x icons"></i>
</div>





<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>

Fiddle: https://jsfiddle.net/zoutepopcorn/v2zkbpay/1/

Johan Hoeksma
  • 3,534
  • 5
  • 28
  • 40
4

Don't be fooled by "great" CSS-only solutions that are actually very browser-specific, or that overlay the styled button on top of the real button, or that force you to use a <label> instead of a <button>, or any other such hack. JavaScript IS necessary to get it working for general usage. Please study how gmail and DropZone do it if you don't believe me.

Just style a normal button however you want, then call a simple JS function to create and link a hidden input element to your styled button.

<!DOCTYPE html>
<meta charset="utf-8">

<style>
    button {
        width            : 160px;
        height           : 30px;
        font-size        : 13px;
        border           : none;
        text-align       : center;
        background-color : #444;
        color            : #6f0;
    }
    button:active {
        background-color : #779;
    }
</style>

<button id="upload">Styled upload button!</button>

<script>

function Upload_On_Click(id, handler) {
    var hidden_input = null;
    document.getElementById(id).onclick = function() {hidden_input.click();}
    function setup_hidden_input() {
        hidden_input && hidden_input.parentNode.removeChild(hidden_input);
        hidden_input = document.createElement("input");
        hidden_input.setAttribute("type", "file");
        hidden_input.style.visibility = "hidden";
        document.querySelector("body").appendChild(hidden_input);
        hidden_input.onchange = function() {
            handler(hidden_input.files[0]);
            setup_hidden_input();
        };
    }
    setup_hidden_input();
}

Upload_On_Click("upload", function(file) {
    console.log("GOT FILE: " + file.name);
});

</script>

Notice how the above code re-links it after every time the user chooses a file. This is important because "onchange" is only called if the user changes the filename. But you probably want to get the file every time the user provides it.

personal_cloud
  • 3,943
  • 3
  • 28
  • 38
  • 1
    To be exact, the `label` approach does work, except it can't show the selected file name or path. So necessarily speaking, that's the only issue one needs JS to solve. – Hassan Baig Oct 29 '17 at 00:59
3

I've found a very easy method to switch the file button to a picture. You just label a picture and place it on top of the file button.

<html>
<div id="File button">
    <div style="position:absolute;">
        <!--This is your labeled image-->
        <label for="fileButton"><img src="ImageURL"></label>
    </div>
    <div>
        <input type="file" id="fileButton"/>
    </div>
</div>
</html>

When clicking on the labeled image, you select the file button.

D-Inventor
  • 81
  • 1
  • 1
3

This week I also needed to custom the button and display the selected file name aside it, so after reading some of the answers above (Thanks BTW) I came up with the following implementation:

HTML:

<div class="browse">
<label id="uploadBtn" class="custom-file-upload">Choose file
<input type="file" name="fileInput" id="fileInput" accept=".yaml" ngf-select ngf-change="onFileSelect($files)" />
</label>
<span>{{fileName}}</span>
</div>

CSS

   input[type='file'] {
    color: #a1bbd5;
    display: none;

}

.custom-file-upload {
    border: 1px solid #a1bbd5;
    display: inline-block;
    padding: 2px 8px;
    cursor: pointer;
}

label{
    color: #a1bbd5;
    border-radius: 3px;
}

Javascript (Angular)

app.controller('MainCtrl', function($scope) {

        $scope.fileName = 'No file chosen';

          $scope.onFileSelect = function ($files) {
          $scope.selectedFile = $files;
          $scope.fileName = $files[0].name;
    };
});

Basically I'm working with ng-file-upload lib, Angular-wise I'm binding the filename to my $scope and giving it the initial value of 'No file chosen', I'm also binding the onFileSelect() function to my scope so when a file gets selected I'm getting the filename using ng-upload API and assign it to the $scope.filename.

liron_hazan
  • 1,396
  • 2
  • 19
  • 27
3

Simply simulate a click on the <input> by using the trigger() function when clicking on a styled <div>. I created my own button out of a <div> and then triggered a click on the input when clicking my <div>. This allows you to create your button however you want because it's a <div> and simulates a click on your file <input>. Then use display: none on your <input>.

// div styled as my load file button
<div id="simClick">Load from backup</div>

<input type="file" id="readFile" />

// Click function for input
$("#readFile").click(function() {
    readFile();
});

// Simulate click on the input when clicking div
$("#simClick").click(function() {
    $("#readFile").trigger("click");
});
James Marquez
  • 365
  • 4
  • 12
3

The best way I have found is having an input type: file then setting it to display: none. Give it an id. Create a button or any other element you want to open the file input.

Then add an event listener on it (button) which when clicked simulates a click on the original file input. Like clicking a button named hello but it opens a file window.

Example code

//i am using semantic ui

<button class="ui circular icon button purple send-button" id="send-btn">
      <i class="paper plane icon"></i>
    </button>
  <input type="file" id="file" class="input-file" />

javascript

var attachButton=document.querySelector('.attach-button');
    attachButton.addEventListener('click', e=>{
        $('#file').trigger("click")
    })
Taio
  • 3,152
  • 11
  • 35
  • 59
2

css can do a lot here... with a little trickery...

<div id='wrapper'>
    <input type='file' id='browse'>
</div>
<style>
    #wrapper {
            width: 93px; /*play with this value */
            height: 28px; /*play with this value */
            background: url('browseBtn.png') 0 0 no-repeat;
            border:none;
            overflow:hidden;
    }

    #browse{
            margin-left:-145px; /*play with this value */
            opacity:0; /* set to .5 or something so you can better position it as an overlay then back to zero again after you're done */
            -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
            filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=0);
    }
</style>

::reference::http://site-o-matic.net/?viewpost=19

-abbey

Jun Yu
  • 375
  • 1
  • 5
  • 21
Abbey
  • 218
  • 3
  • 7
2

As JGuo and CorySimmons mentioned, you can use the clickable behaviour of a stylable label, hiding the less flexible file input element.

<!DOCTYPE html>
<html>
<head>
<title>Custom file input</title>
<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">
</head>

<body>

<label for="upload-file" class="btn btn-info"> Choose file... </label>
<input id="upload-file" type="file" style="display: none"
onchange="this.nextElementSibling.textContent = this.previousElementSibling.title = this.files[0].name">
<div></div>

</body>
</html>
Community
  • 1
  • 1
KitKat
  • 1,495
  • 14
  • 15
2

The best way is using the pseudo element :after or :before as an element overt the de input. Then style that pseudo element as you wish. I recomend you to do as a general style for all input files as follows:

input {
  height: 0px;
  outline: none;
}

input[type="file"]:before {
  content: "Browse";
  background: #fff;
  width: 100%;
  height: 35px;
  display: block;
  text-align: left;
  position: relative;
  margin: 0;
  margin: 0 5px;
  left: -6px;
  border: 1px solid #e0e0e0;
  top: -1px;
  line-height: 35px;
  color: #b6b6b6;
  padding-left: 5px;
  display: block;
}
Despertaweb
  • 1,672
  • 21
  • 29
2

A demo for image upload application suitable for most of the backend with nice animation features.

// common
function render_element(styles, el) {
    for (const [kk, vv] of Object.entries(styles)) {
        el.style[kk] = vv;
    }
}

function hoverOpacity(el) {
    el.addEventListener('mouseenter', function() {
        el.style.opacity = 0.75
    }.bind(el));
    el.addEventListener('mouseleave', function() {
        el.style.opacity = 1
    }.bind(el));
}

// return void event handler on setTimeout
function buffer(func, time){
    return e=>{
        if(func.still)return;
        // first runtime
        if(!func.pft){
            func(e);
            func.pft = true;
            func.still = false;
            return;
        }
        func.still = true;
        setTimeout(e=>{
            func(e);
            func.still = false;
        }, time);
    }
}
// end of common

const imageUploadButton = document.getElementById('image-upload-button');
imageUploadButton.addEventListener('click', e=>{
    // pulse animation total time
    const d1 = document.getElementById('image-form');
    let time = 600;

    if(d1.rendered){
        d1.ready();
    }else{
        d1.ready = function(){
            d1.style.display = 'flex';
            d1.style.background = '#c5edd0';
            this.d2.style.background = '#b4dbbf';
            this.d3.style.background = '#95dea9';
            this.d4.innerHTML = 'Drag and Drop or Click Above to Upload';
        }
        let dismiss_btn = document.createElement('div');
        render_element({
            position: 'absolute',
            height: '30px',
            width: '30px',
            top: '0', 
            right: '0',
            background: '#fff',
            borderRadius: '30px',
            cursor: 'pointer', 
            margin: '2px',
            zIndex: '10',
        }, dismiss_btn);
        dismiss_btn.addEventListener('mouseenter', function(){this.style.background = '#fc4f30'});
        dismiss_btn.addEventListener('mouseleave', function(){this.style.background = '#fff'});
        dismiss_btn.addEventListener('click', ()=>{d1.style.display = 'none'});
        d1.appendChild(dismiss_btn);
        const d3 = d1.querySelector('#image-input');
        const d5 = d1.querySelector('#image-submit');
        d5.style.visibility = 'hidden';
        d1.parentNode.removeChild(d1);
        document.body.appendChild(d1);
        d1.removeChild(d3);
        let [
            d2, 
            d4, 
        ] = Array.from({length: 3}, ()=>document.createElement('div'));
        let width = window.innerWidth;
        let d_styles = {
            display: 'flex',
            justifyContent: 'center', 
            alignItems: 'center',
        };
        render_element({
            position: 'fixed',
            left: ((width - 430) / 2).toString() + 'px', 
            width: '430px',
            top: '60px',
            height: '280px',
            zIndex: '10', 
        }, d1);
        render_element(d_styles, d1);

        render_element({
            width: '90%',
            height: '90%', 
        }, d2);
        render_element(d_styles, d2);

        render_element({
            width: '80%',
            height: '70%', 
            fontSize: '0',
            cursor: 'pointer',
        }, d3);
        hoverOpacity(d3);
        render_element(d_styles, d3);

        d1.appendChild(d2);
        d2.appendChild(d3);

        let tt = time / 3;
        let ht = tt / 2;
        d1.addEventListener('dragover', buffer(e=>{
            d1.style.background = '#ebf9f0';
            setTimeout(()=>{
                d1.style.background = '#95dea9';
            }, ht);
            setTimeout(()=>{
                d2.style.background = '#b6e3c2';
                setTimeout(()=>{
                    d2.style.background = '#c4eed2';
                }, ht);
            }, tt);
            setTimeout(()=>{
                d3.style.background = '#cae3d1';
                setTimeout(()=>{
                    d3.style.background = '#9ce2b4';
                }, ht);
            }, tt);
        }, time));

        d2.style.flexDirection = 'column';
        render_element({
            fontSize: '16px',
            textAlign: 'center',
            fontFamily: 'Verdana',
        }, d4);
        d2.appendChild(d4);

        d3.addEventListener('change', e=>{
            // backend
            // d5.click();
            // if backend succeed, run frontend
            setTimeout(()=>{
                d1.style.background = '#dbcea2';
                setTimeout(()=>{
                    d2.style.background = '#dbc169';
                    setTimeout(()=>{
                        d3.style.background = '#ebc034';
                    }, ht);
                }, tt);
            }, time);
            // display backend path here
            // now only display filename
            d4.innerHTML = d3.files[0].name;
        });
        d1.d2 = d2;
        d1.d3 = d3;
        d1.d4 = d4;
        d1.ready();
        d1.rendered = true;
    }
});
#image-upload-button{
    width: 200px;
    height: 40px;
    background: lightgrey;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

#image-form{
    display: none;
}

::-webkit-file-upload-button {
    visibility: hidden;
}
<div id="image-upload-button">Upload Image
    <form id="image-form" action="post">
        <input id="image-input" type="file" />
        <button id="image-submit" type="submit"></button>
    </form>
</div>
Weilory
  • 2,621
  • 19
  • 35
1

Here's a simple css only solution, that creates a consistent target area, and lets you style your faux elements however you like.

The basic idea is this:

  1. Have two "fake" elements (a text input/link) as siblings to your real file input. Absolutely position them so they're exactly on top of your target area.
  2. Wrap your file input with a div. Set overflow to hidden (so the file input doesn't spill out), and make it exactly the size that you want your target area to be.
  3. Set opacity to 0 on the file input so it's hidden but still clickable. Give it a large font size so the you can click on all portions of the target area.

Here's the jsfiddle: http://jsfiddle.net/gwwar/nFLKU/

<form>
    <input id="faux" type="text" placeholder="Upload a file from your computer" />
    <a href="#" id="browse">Browse </a>
    <div id="wrapper">
        <input id="input" size="100" type="file" />
    </div>
</form>
Kerry Liu
  • 2,072
  • 16
  • 16
  • Hi Kerry, Your code is working fine for styling the button but when we select the file, the placeholder should also get changed. Please can you assist for the same? Is is possible to change the place holder after selecting file? – Khushbu Vaghela Feb 18 '20 at 04:48
1

In case you're looking for a javascript library - out of the box solution, jquery-fileinput works fine.

ellimilial
  • 1,246
  • 11
  • 20
1

These answers are nice, and they all work for very specific use cases. That is to say, they are opinionated.

So, here's an answer that assumes nothing, but will work no matter how you modify it. You can change design with css, add javascript to maybe show a file name on change, etc. it will still always work.

Code:

Here is the core css

.file-input{
  pointer-events: none;
  position: relative;
  overflow: hidden;
}
.file-input > * {
  pointer-events: none;
}
.file-input > input[type="file"]{
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  opacity: 0;
  pointer-events: all;
  cursor: pointer;
  height: 100%;
  width: 100%;
}

and the core html:

<div class="file-input">
  <input type="file"/>
</div>

As you can see, we are forcing any pointer event(click) that happens on the .file-input element, or any of its children, to be proxied to the file input. This is because the file input is positioned absolute and will consume the width/height of the container always. You can therefore customize to fit your need. style the wrapper into a button, use some js to display file name on select, etc. nothing will break so long as the above core code remains intact.

As you will see in the demo, i have added a span with text "Select file" and a class with extra styles to style the .file-input div. This should be the canonical starting point for anyone intending to create a custom file upload element.

Demo:JSFIDDLE

r3wt
  • 4,642
  • 2
  • 33
  • 55
1

You can make an awesome ( unfinished ) File Uploader to a <button> element or any other element:

function selectFile() {
    document.getElementById("fileSelector").click();
}
input#fileSelector[type="file"] {
    display: none;
}

button[onclick*="()"] {
    cursor: pointer;
}
<input type="file" id="fileSelector">
<button onclick="selectFile()">Select file from computer...</button>
RixTheTyrunt
  • 185
  • 3
  • 11
1

There are a lot of solutions here but I wanted to add something with modern considerations in mind. No hidden or visibility hacks. JS will still be needed to enhance with feedback and drag & drop.

The key is in setting the button to 100% width;

[type="file"]::file-selector-button {
  width: 100%;
}

[type="file"] {
  width: 50%;
  min-width: 14ch;
}

[type="file"]::file-selector-button {
  width: 100%;
  margin-inline-end: 0;
  padding: 0.6rem;
  background-color: lightblue;
  color: smoke;
  border: none;
  border-radius: 0;
  text-transform: uppercase;
}
<input type="file" />
Joel Stransky
  • 380
  • 1
  • 5
  • 17
0

jquery version of teshguru script for automatically detect input[file] and style

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<style>
#yourBtn{
   position: relative;
       top: 150px;
   font-family: calibri;
   width: 150px;
   padding: 10px;
   -webkit-border-radius: 5px;
   -moz-border-radius: 5px;
   border: 1px dashed #BBB; 
   text-align: center;
   background-color: #DDD;
   cursor:pointer;
  }
</style>
<script type="text/javascript">
$(document).ready(function()
{
    $('input[type=file]').each(function()
    {
        $(this).attr('onchange',"sub(this)");
        $('<div id="yourBtn" onclick="getFile()">click to upload a file</div>').insertBefore(this);
        $(this).wrapAll('<div style="height: 0px;width: 0px; overflow:hidden;"></div>');
    });
});
 function getFile(){
   $('input[type=file]').click();
 }
 function sub(obj){
    var file = obj.value;
    var fileName = file.split("\\");
    document.getElementById("yourBtn").innerHTML = fileName[fileName.length-1];
 }
</script>
</head>
<body>
<?php 
    var_dump($_FILES);
?>
<center>
<form action="" method="post" enctype="multipart/form-data" name="myForm">

<input id="upfile" name="file" type="file" value="upload"/>
<input type="submit" value='submit' >
</form>
</center>
</body>
</html>
h0mayun
  • 3,466
  • 31
  • 40
0

Plug-in solutions I found were too heavy-weight, so, I made my own jQuery plug-in called Drolex FileStyle.

This plug-in allows you to style file input fields however you want. Actually, you style div elements to look like a tricked out file input, and the actual file input is automatically overlaid with 0% opacity. No additional HTML is required. Just include the css and js files in the page you want Drolex FileStyle and that's it! Edit the css file to your liking. Don't forget the jQuery library if your page doesn't already have it. If the client does not run JavaScript, then the file input will not be modified by js or css.

Tested to work in Chrome 24, Firefox 18, Internet Explorer 9. Expected to work in previous versions of those and others.

Download: http://web.drolex.net/Drolex-FileStyle.zip

drolex
  • 4,993
  • 1
  • 18
  • 14
0

A really clever solution using jQuery that works in all older browsers as well as in the new ones, I found here. It takes care of all the styling and click() problems, using the actual file browse button. I made a plain javascript version: fiddle The solution is as simple as genius: make the file-input invisible, and use a piece of code to place it under the mousecursor.

<div class="inp_field_12" onmousemove="file_ho(event,this,1)"><span>browse</span>
    <input id="file_1" name="file_1" type="file" value="" onchange="file_ch(1)">
</div>
<div id="result_1" class="result"></div>
<script>
    function file_ho(e, o, a) {
        e = window.event || e;
        var x = 0,
        y = 0;
        if (o.offsetParent) {
            do {
            x += o.offsetLeft;
            y += o.offsetTop;
            } while (o = o.offsetParent);
        }
    var x1 = e.clientX || window.event.clientX;
    var y1 = e.clientY || window.event.clientY;
    var le = 100 - (x1 - x);
    var to = 10 - (y1 - y);
    document.getElementById('file_' + a).style.marginRight = le + 'px';
    document.getElementById('file_' + a).style.marginTop = -to + 'px';
    }
</script>
<style>
    .inp_field_12 {
        position:relative;
        overflow:hidden;
        float: left;
        width: 130px;
        height: 30px;
        background: orange;
    }
    .inp_field_12 span {
        position: absolute;
        width: 130px;
        font-family:'Calibri', 'Trebuchet MS', sans-serif;
        font-size:17px;
        line-height:27px;
        text-align:center;
        color:#555;
    }
    .inp_field_12 input[type='file'] {
        cursor:pointer;
        cursor:hand;
        position: absolute;
        top: 0px;
        right: 0px;
        -moz-opacity:0;
        filter:alpha(opacity=0);
        opacity: 0;
        outline: none;
        outline-style:none;
        outline-width:0;
        ie-dummy: expression(this.hideFocus=true);
    }
    .inp_field_12:hover {
        background-position:-140px -35px;
    }
    .inp_field_12:hover span {
        color:#fff;
    }
</style>
Jun Yu
  • 375
  • 1
  • 5
  • 21
Michel
  • 4,076
  • 4
  • 34
  • 52
0

Here's a cross compatible method which will work in Chrome, Firefox, Safari, and IE.

$(window).on('resize',function() {
 var eqw = $('input[type=text]').width();
 $('textarea').width(eqw - 32);
 $('.fileoutline').width(eqw);
}).trigger('resize');

$('.file+.file').hide();

$(".file").click(function() {
    var input = $(this).next().find('input');
    input.click();
});
$("input[id='file1']").change(function () {
 $('.file+.file').show();
 var filename = $(this).val();
 $('.filename1').html(filename);
 $('.file').find('span').html('CHANGE FILE');
});
$("input[id='file2']").change(function() {
 var filename = $(this).val();
 $('.filename2').html(filename);
 $('.file').find('span').html('CHANGE FILE');
});
 
form { width:55%;margin:0 auto;padding-left:3vw;text-align:left; }
fieldset{border:0;margin:0;padding:0;}
textarea{overflow: auto;height:25vh;resize:none;outline:none;width:93%;background:none;padding:8px 15px;display:block;text-align:left;border:1px solid #000;margin:0;color:#000;font:700 0.85em/2.2 'Futura Book',Arial,sans-serif;}
input:focus{outline:none;}
input[type=text]{font-weight:700;font-size:0.85em;line-height:2.2;background:none;text-align:left;letter-spacing:0.02em;height:33px;display:block;width:100%;border:none;border-bottom:1px solid #000;margin:0 0 28px;color:#000;}
input:focus{outline:0;}
.fileoutline { width:100%;margin:25px auto 0px;left:0;right:0;height:40px;border:1px solid #000;position:relative; }
input[type=file] { -webkit-appearance: none;-moz-appearance:none;appearance: none;opacity:0;position:relative;width:100%;height:35px;font-weight:700;font-size:0.5em;line-height:28px;letter-spacing:0.2em;position: absolute;left: 0;top: 0;height: 100%;z-index:10; }
.file,.filename1,.filename2,#submit { font-size:10px;letter-spacing:0.02em;text-transform:uppercase;color:#ffffff;text-align:center;width:35%;}
.file,.filename1,.filename2 { font-weight:200;line-height:28px;}
.filename1,.filename2 { width:375px;overflow:hidden;top:0;text-align:right;position:absolute;display:block;height:26px;color:#000;}
.file { position:absolute;width:100px;top:6px;left:10px;background:#000;border-radius:14px; }
::-webkit-file-upload-button,::-ms-browse { width: 100%;height:25px;opacity: 0;-webkit-appearance: none;appearance: none; }
#submit{border:none;height:32px;background: #000;box-shadow:0 0 0 0.5px #fff,0 0 0 5px #000;margin:35px 0;float:right;display:block;}
<form action="" method="post" enctype="multipart/form-data">
    <input type="text" name="email" id="email" placeholder="Email address" />
    <input type="text"  type="text" name="name" id="title" placeholder="Name" />
    <textarea rows="7" cols="40" name="description" id="description" placeholder="Description"></textarea>
    <div class="fileoutline"><div class="file"><span>CHOOSE FILE</span><input type="file" name="file[]" id="file1"><div class="filename1">NO CHOSEN FILE</div></div></div>
    <div class="fileoutline"><div class="file"><span>CHOOSE FILE</span><input type="file" name="file[]" id="file2"><div class="filename2">NO CHOSEN FILE</div></div></div>
    <input type="submit" name="submit" value="Submit" id="submit">
</form>
davidcondrey
  • 34,416
  • 17
  • 114
  • 136
0

If anyone still cares on how to do this without JavaScript, let me complete Josh answer:

How to display the text of the filename:

The easiest way is to set both elements to a position:relative, give the label a higher z-index and give the input file negative margin until the label text is where you want it to be. Do not use display:none on the input!

Example:

input[type="file"] {
  position:relative;
  z-index:1;
  margin-left:-90px;
}

.custom-file-upload {
  border: 1px solid #ccc;
  display: inline-block;
  padding: 6px 12px;
  cursor: pointer;
  position:relative;
  z-index:2;
  background:white;

}
KoU_warch
  • 2,160
  • 1
  • 25
  • 46
  • I really wanted something like this to maintain the text, but this didn't work for me, FF and chrome both still showed the standard grey button to the left (if that was not shown it would have looked pretty good). IE 11 didn't like it at all. – dading84 Mar 10 '16 at 13:11
  • Yep, lots of people care to do this with pure CSS. But it needs to be robust across user agents, which it isn't. – Hassan Baig Oct 29 '17 at 01:04
0

I found this approach the simplest and lightest.

Here is the working example: http://codepen.io/c3zar22/pen/QNoYXN

Below are the explanations:

  • this would be the markup:

    <label for="attach-project-file">
        <span id="remove-project-file" class="close">x</span>
        <div class="filename" id="attached-project-file">Click to select a file</div>
    </label>
    <input id="attach-project-file" type="file">
    
  • hide the input in a hacky way like this:

    #attach-project-file {
        width: 0.1px;
        height: 0.1px;
        opacity: 0;
        overflow: hidden;
        position: absolute;
        z-index: -1;
    }
    
  • style the corresponding label instead

    [for="attach-project-file"] {
        /* your styles here */
    }
    
  • style "remove file" button

    .close {
        font-size: 16px;
        padding: 10px;
        position: absolute;
        top: 0;
        right: 0;
        cursor: pointer;
        font-style: normal;
    }
    
  • .filename element will be used to display the selected file

  • below is the commented JS code needed (using jQuery) to make it work:

    var $attach = $('#attach-project-file'),
        $remove = $('#remove-project-file'),
        $name = $('#attached-project-file');
    
    // initially hide the remove button
    $remove.hide();
    
    // do this when file input has changed
    // i.e.: a file has been selected
    $attach.on('change', function() {
        var val = $(this).val();
        if (val !== '') {
            // if value different than empty
    
            // show the file name as text
            // hide/text/fadeIn creates a nice effect when changing the text
            $name
                .hide()
                .text(val)
                .fadeIn();
    
            // show the remove button
            $remove.fadeIn();
        } else {
            // if value empty, means the file has been removed
    
            // show the default text
            $name
                .hide()
                .text('Click to select a file')
                .fadeIn();
    
            // hide remove button
            $remove.fadeOut();
        }
    });
    
    // remove selected file when clicking the remove button
    // prevent click bubbling to the parent label and triggering file selection
    $remove.on('click', function(e) {
        e.preventDefault();
        e.stopPropagation();
    
        $attach
            .val('')
            .change(); // trigger change event
    });
    
Cezar D.
  • 356
  • 1
  • 6
  • 12
0

A quick and crude way is to set the label as a button and set position to absolute so it floats over original button, you still see file name. I am thinking about a mobile solution however.

Tomas Crofty
  • 189
  • 2
  • 12
0

The more recent suggestions to use both [type="file"] and [type="file"]::file-selector-button were great tips, but the solutions target every file input in the site rather than just the element in hand.

To hide the chosen text (this is what I was looking for), the only attribute that needs adjusting is the width on the input and the button (they should match).

To target just a subset of file inputs, set a custom class on the <input> element (e.g. class="custom-fileinput") then use this in your selector constructs.

For my need, to hide the chosen file text, I ended up with the following css:

.custom-fileinput, .custom-fileinput::file-selector-button {
    width: 12em;
}