Twitter Bootstrap Form File Element Upload Button
Asked Answered
D

27

611

Why isn't there a fancy file element upload button for twitter bootstrap? It would be sweet if the blue primary button was implemented for the upload button. Is it even possible to finesse the upload button using CSS? (seems like a native browser element that can't be manipulated)

Delogu answered 27/6, 2012 at 21:41 Comment(1)
You can find it here. markusslima.github.io/bootstrap-filestyleOctroi
S
1027

Here's a solution for Bootstrap 3, 4, and 5.

To make a functional file input control that looks like a button, you only need HTML:

HTML

<label class="btn btn-default">
    Browse <input type="file" hidden>
</label>

This works in all modern browsers, including IE9+. If you need support for old IE as well, please use the legacy approach shown below.

This techniques relies on the HTML5 hidden attribute. Bootstrap 4 uses the following CSS to shim this feature in unsupportive browsers. You may need to add if you're using Bootstrap 3.

[hidden] {
  display: none !important;
}

Legacy approach for old IE

If you need support for IE8 and below, use the following HTML/CSS:

HTML

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

CSS

.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;
}

Note that old IE doesn't trigger the file input when you click on a <label>, so the The CSS "bloat" does a couple things to work around that:

  • Makes the file input span the full width/height of the surrounding <span>
  • Makes the file input invisible

Feedback & Additional Reading

I've posted more details about this method, as well as examples for how to show the user which/how many files are selected:

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

Satinwood answered 10/8, 2013 at 17:30 Comment(27)
+ 1 For me this is by far the best answer. Very concise solution using the latest version of bootstrap.Bausch
@qub1n Follow the link to the article for an example of how to do that.Satinwood
Could anyone explain why this doesn't work with Bootstrap 2 in Firefox and IE? (latest versions IE11 and FF 32.0.3 on Windows 8). Works fine on Chrome and Safari, but no response when you click the button on IE and FF.Paulina
Thanks for this. I'm new to CSS and Boostrap - if I wanted to place something immediately to the right of the input (used as your input group example with the file name showing), how would I do that? For example, another button to clear the input field. At the moment, I think the min-width and text-align is forcing anything placed after the text field to appear below it.Semitrailer
Awesome. Some may want to add something like: display: block; width: 100px;Blunderbuss
@Bausch @JaredEitnier @IvanWang I respectfully disagree. And offer a shameless plug to my answer which simply uses the <label> element. As the best solution :)Atalya
I have to agree with @KirillFuchs; label would be better. Plus - the user can't see if they selected the right file because the button doesn't show the selected file name: jsfiddle.net/36o9pdf9/1Publication
Label would be semantically better. Check out the article for a method of showing which files are selected. (Some apps auto-upload when a file is selected, so in those cases filename feedback isn't critical.)Satinwood
This is nice, but how do I make thew image upload once it's selected?Theodore
I couldn't get this to work on IE11 together with a FormData object. Somehow IE is ignoring the input field when it is inside a label element, and as a result the file data is not available from the FormData object.Balcony
Best solution I have found so far. Some improvements would be to get the button to show focus. Also, this button doesn't participate well in button groups, since its not a real button. But still great solution.Richellericher
Works fine in button groups (see demo).Satinwood
Something to be aware of is regular file inputs trigger when a person selects the input, not just the button. Perhaps more JS is necessary.Ustkamenogorsk
When I copy/pasted the answer the cursor on the 'browse...' button wasn't always a pointer, but sometimes the default arrow. I wanted this to be the pointer on the complete button. Changing the css selecter to .btn-file > input[type='file'] fixed this problem.Sealed
I just ran into what I, at first, thought was an interaction of this code and Internet Explorer. HOWEVER, I found that the problem with IE was due to a "//" style comment I had placed inside the <style> section. The effect was to show a large blinking cursor, if I had this comment!!! That's really odd!Volny
Thanks for this post, it helped me clean up the styling of my site that uses a input file element. However I encountered an issue with the .btn-file input[type=file] rules in that the font-size: 100px property was causing issues when tabbing through input elements on the page. Changing the value of this property 10px resolved the issue for me. Unsure if that was just a typo or was set to that on purpose, but wanted to share. Cheers.Mastoiditis
This seems to work the best of the many similar solutions. It even works w/keyboard navigation ... except that you cannot see the focus indicator when the input receives focus. I'm wondering if there's some trick that can be done by wrapping the the input w/something that can receive focus... but that feels like it'd require javascript.Beekeeping
Note that this solution seemingly contains some unnecessary CSS bloat.Corneliuscornell
This doesn't work at all in firefox I'm afraid. Answer by Kirill is perfectEpicycloid
This works fine in the latest Firefox. See the CodePen demo. I use it in a number of projects and production apps without complaint.Satinwood
This doesn't work in Chrome (at least). The input isn't hidden by the hidden attribute once Bootstrap is there. Also btn-file isn't valid Bootstrap CSS. jsfiddle.net/o6ua83sgHolbein
Chuck, it works perfectly fine in Chrome. Your example was missing the required CSS and your HTML wasn't structured according to my answer (the input needs to be inside the label). Here's a modified example: jsfiddle.net/zsmfyvL9 The btn-file class is custom. It's not part of Bootstrap, but it follows a similar convention for those who prefer consistency.Satinwood
Not sure why I'm even bothering to help you at this point. Obviously hundreds, if not thousands, of people have figured it out. Here's to the special ones that need a little extra hand holding. 🍻 Since you didn't specify whether you're using the legacy approach or the modern approach, I made an assumption. Here's your fiddle again with yet another example: jsfiddle.net/coz70ng1 This assumes Bootstrap 4, which shims the hidden attribute in unsupportive browsers.Satinwood
It's being overridden with the following bootstrap style: input[type="file"] { display: block; } - so i will have to use simple-n-dirty solution with style="display: none" :)Cacography
You could also just add class="hidden" on the input, no need for custom css.Lens
Bootstrap 4 shims the hidden attribute using that CSS so you don't even need a class. I've added it for those who want BS3 compatibility.Satinwood
I'm with Krill Fuchs (find his answer above). His answer is short, sweet, and behaves correctly. I have some JS wrapped around my file input and it continued to work perfectly with Krill's solution.Allanite
A
410

Im surprised there was no mention of the <label> element.

Solution:

<label class="btn btn-primary" for="my-file-selector">
    <input id="my-file-selector" type="file" class="d-none">
    Button Text Here
</label>

No need for any JS, or funky css...

Solution for including the filename:

<label class="btn btn-primary" for="my-file-selector">
    <input id="my-file-selector" type="file" style="display:none" 
    onchange="$('#upload-file-info').text(this.files[0].name)">
    Button Text Here
</label>
<span class='label label-info' id="upload-file-info"></span>

The solution above requires jQuery.

Note: use $.text() when displaying user-supplied content on the page. An earlier version of this answer used $.html() which is not safe – filenames can contain HTML markup.

Atalya answered 31/7, 2014 at 8:17 Comment(23)
This answer should be the accepted one. It's even better than @claviska's answerKirstenkirsteni
Nice touch using label. I'll have to test for legacy browser support. You'll also still need JS if you want to show selected files (although I suspect most apps auto-upload as soon as a selection is made).Satinwood
Tested this out and it works in everything but < IE9.Satinwood
Can't quite understand why this isn't the accepted answer. Clean, simple and stable (unless you're targetting < IE9, that is...)Aziza
I couldn't get this to work on IE11 together with a FormData object. Somehow IE is ignoring the input field when it is inside a label element, and as a result the file data is not available from the FormData object.Balcony
@FernandoCarvalhosa So? ;)Impassive
When I shrink my window the button text will get cut off.Richellericher
@Impassive So...what? Didn't get it, sorry.Kirstenkirsteni
I was saying "so what if it doesn't work in IE". Joke.Impassive
well, it doesn't display which file is choosed(Amir
Thanks! This answer actually worked, whereas the accepted answer did not.Motorman
One problem w/this solution is that by setting display: none on the input you are then unable to focus the input using keyboard navigation. Pressing tab skips right over the hidden input. Any ideas?Beekeeping
You don't need to use for if you're wrapping the target element with the label.Gurtner
I used width: 0px; height: 0px to make it selectable by keyboard while there's still no space allocated for it.Jenine
If you want to see a filename of file to upload, you can combine this answer with @codefreak answer and add onchange="$('#upload-file-info').html($(this).val());" to the input and <span class='label label-info' id="upload-file-info"></span> right after closing the labelAnsela
I tweaked it to: onchange="$('#upload-file-info').html($(this).val().replace('C:\\fakepath', '...'));" As the 'C:\fakepath' thing looks a bit naff.Vivianviviana
I tweaked it to show only the file name without C://fakepath as follows: onchange="$('#upload-file-info').html(this.files[0].name);"Severson
how could I get the error message when file is not selected ?Grief
Wish this had worked-- a very good solution! However, it doesn't take advantage of the native localization. A default file input will say "Choose file" (or whatever that browser implementation says) whereas this one needs label text. Nothing the author of this answer can do to resolve this, but it's unfortunate.Partible
This works except I have the button alongside another button and this one is too high, how do I get the label and button aligned (note if I change the label element to button then it is aligned correctly but then of course doesnt work.Mintamintage
This works in general but if I want to align the button to the center then the button is not anymore clickable. Anyone has solution for this problem?Hindward
for label alignment have slightly out of position due to the label have margin-bottom of .5em, you can create a class which set the margin-bottom to 0 for that label, this will solve your alignment issueDragging
It is worth saying this does not work with keyboard navigation, if anyone has a solution ?Philoctetes
S
136

With no additional plugin required, this bootstrap solution works great for me:

<div style="position:relative;">
        <a class='btn btn-primary' href='javascript:;'>
            Choose File...
            <input type="file" style='position:absolute;z-index:2;top:0;left:0;filter: alpha(opacity=0);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";opacity:0;background-color:transparent;color:transparent;' name="file_source" size="40"  onchange='$("#upload-file-info").html($(this).val());'>
        </a>
        &nbsp;
        <span class='label label-info' id="upload-file-info"></span>
</div>

demo:

http://jsfiddle.net/haisumbhatti/cAXFA/1/ (bootstrap 2)

enter image description here

http://jsfiddle.net/haisumbhatti/y3xyU/ (bootstrap 3)

enter image description here

Sherd answered 21/2, 2013 at 7:2 Comment(6)
I had some issues with the bottom area of the button not clickable. This answer helped me in bootstrap 3: https://mcmap.net/q/48989/-twitter-bootstrap-form-file-element-upload-buttonBobwhite
This is an excellent solution as it shows the file name of the attached file!Distemper
Could someone please explain the need for the href='javascript:;' ? I don't need the onchange='$("#upload-file-info").html($(this).val());' to update the upload-file-info element, but the file upload dialog won't trigger without the href.Paulina
Where is 'C:\fakepath' coming from and how do I get rid of it?Campobello
@Campobello C:\fakepath is html5 security feature and is prefixed to file path if we manipulate it with javascript. See this blog post davidwalsh.name/fakepath for details.Sherd
What about multiple file support for "2 files" etc...?Drunken
E
90

It's included in Jasny's fork of bootstrap.

A simple upload button can be created using

<span class="btn btn-file">Upload<input type="file" /></span>

With the fileupload plugin you can create more advanced widgets. Have a look at http://jasny.github.io/bootstrap/javascript/#fileinput

Ethyl answered 16/10, 2012 at 13:10 Comment(4)
Does this work ok in IE9? I'm asking because I assume the solution makes use of Javascript, and, at the same time, "the IE doesn’t allow manipulation of the type=”file” input element from javascript due to security reasons."Covalence
Yes it works in IE9 as well. It sets the opacity of the input element to 0, which luckily works in all browsers :). It's explained in the quirksmode article.Ethyl
it does not work with jQuery 1.9.0, because they dropped $.browser supportOngoing
Looks terrible with regular bootstrap - img688.imageshack.us/img688/948/pictureui.pngDieback
H
66

Upload buttons are a pain to style because it styles the input and not the button.

but you can use this trick:

http://www.quirksmode.org/dom/inputfile.html

Summary:

  1. Take a normal <input type="file"> and put it in an element with position: relative.

  2. To this same parent element, add a normal <input> and an image, which have the correct styles. Position these elements absolutely, so that they occupy the same place as the <input type="file">.

  3. Set the z-index of the <input type="file"> to 2 so that it lies on top of the styled input/image.

  4. Finally, set the opacity of the <input type="file"> to 0. The <input type="file"> now becomes effectively invisible, and the styles input/image shines through, but you can still click on the "Browse" button. If the button is positioned on top of the image, the user appears to click on the image and gets the normal file selection window. (Note that you can't use visibility: hidden, because a truly invisible element is unclickable, too, and we need the to remain clickable)

Hasson answered 27/6, 2012 at 21:59 Comment(2)
This is way too much work for these days. Using something ready like Jasny's solution in next answer makes a lot more sense.Whitebait
If your example includes support for supporting netscape, it's probably not up to date.Courtier
C
22

Works for me:

Update

jQuery plugin style:

// Based in: http://duckranger.com/2012/06/pretty-file-input-field-in-bootstrap/
// Version: 0.0.3
// Compatibility with: Bootstrap 3.2.0 and jQuery 2.1.1
// Use:
//     <input class="nice_file_field" type="file" data-label="Choose Document">
//     <script> $(".nice_file_field").niceFileField(); </script>
//
(function( $ ) {
  $.fn.niceFileField = function() {
    this.each(function(index, file_field) {
      file_field = $(file_field);
      var label = file_field.attr("data-label") || "Choose File";

      file_field.css({"display": "none"});

      nice_file_block_text  = '<div class="input-group nice_file_block">';
      nice_file_block_text += '  <input type="text" class="form-control">';
      nice_file_block_text += '  <span class="input-group-btn">';
      nice_file_block_text += '   <button class="btn btn-default nice_file_field_button" type="button">' + label + '</button>';
      nice_file_block_text += '  </span>';
      nice_file_block_text += '</div>';

      file_field.after(nice_file_block_text);

      var nice_file_field_button = file_field.parent().find(".nice_file_field_button");
      var nice_file_block_element = file_field.parent().find(".nice_file_block");

      nice_file_field_button.on("click", function(){ console.log("click"); file_field.click() } );
      file_field.change( function(){
        nice_file_block_element.find("input").val(file_field.val());
      });
    });
  };
})( jQuery );
Calorific answered 5/12, 2012 at 20:19 Comment(0)
H
18

Simplified answer using parts from other answers, primarily user2309766 and dotcomsuperstar.

Features:

  • Uses Bootstrap button addon for button and field.
  • Only one input; multiple inputs would be picked up by a form.
  • No extra css except "display: none;" to hide the file input.
  • Visible button fires click event for hidden file input.
  • split to remove file path uses regex and delimiters '\' and '/'.

Code:

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div class="input-group">
  <span class="input-group-btn">
    <span class="btn btn-primary" onclick="$(this).parent().find('input[type=file]').click();">Browse</span>
    <input name="uploaded_file" onchange="$(this).parent().parent().find('.form-control').html($(this).val().split(/[\\|/]/).pop());" style="display: none;" type="file">
  </span>
  <span class="form-control"></span>
</div>
Hindorff answered 27/5, 2015 at 17:29 Comment(0)
G
13

With some inspiration from other posts above, here is a full solution that combines what looks like a form-control field with an input-group-addon for a clean file input widget that includes a link to the current file.

.input-file { position: relative; margin: 60px 60px 0 } /* Remove margin, it is just for stackoverflow viewing */
.input-file .input-group-addon { border: 0px; padding: 0px; }
.input-file .input-group-addon .btn { border-radius: 0 4px 4px 0 }
.input-file .input-group-addon input { cursor: pointer; position:absolute; width: 72px; z-index:2;top:0;right:0;filter: alpha(opacity=0);-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";opacity:0; background-color:transparent; color:transparent; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<div class="input-group input-file">
  <div class="form-control">
    <a href="/path/to/your/current_file_name.pdf" target="_blank">current_file_name.pdf</a>
  </div>
  <span class="input-group-addon">
    <a class='btn btn-primary' href='javascript:;'>
      Browse
      <input type="file" name="field_name" onchange="$(this).parent().parent().parent().find('.form-control').html($(this).val());">
    </a>
  </span>
</div>
Gourd answered 14/12, 2014 at 7:37 Comment(0)
G
9

This works perfectly for me

<span>
    <input  type="file" 
            style="visibility:hidden; width: 1px;" 
            id='${multipartFilePath}' name='${multipartFilePath}'  
            onchange="$(this).parent().find('span').html($(this).val().replace('C:\\fakepath\\', ''))"  /> <!-- Chrome security returns 'C:\fakepath\'  -->
    <input class="btn btn-primary" type="button" value="Upload File.." onclick="$(this).parent().find('input[type=file]').click();"/> <!-- on button click fire the file click event -->
    &nbsp;
    <span  class="badge badge-important" ></span>
</span>
Gainer answered 23/4, 2013 at 4:44 Comment(0)
A
9

Please check out Twitter Bootstrap File Input. It use very simple solution, just add one javascript file and and paste following code:

$('input[type=file]').bootstrapFileInput();
Abdominous answered 19/4, 2015 at 9:33 Comment(3)
Link is broken (July 2019)Daron
@Daron yes, it's broken nowAbdominous
@Yetti99, I changed the link. Please check now.Abdominous
S
6

A simple solution with acceptable outcome:

<input type="file" class="form-control">

And the style:

input[type=file].form-control {
    height: auto;
}
Sheeran answered 14/3, 2014 at 12:49 Comment(0)
D
5

Solution for multiple upload

I tweaked two previous answers to include multiple uploads. In this way the label shows the file name, if only one is selected, or x files in the opposite case.

<label class="btn btn-primary" for="my-file-selector">
    <input id="my-file-selector" type="file" multiple="multiple" style="display:none"
        onchange="$('#upload-file-info').html(
            (this.files.length > 1) ? this.files.length + ' files' : this.files[0].name)">                     
    Files&hellip;
</label>
<span class='label label-info' id="upload-file-info"></span>

enter image description here

It may also apply to change the button text and class.

<label class="btn btn-primary" for="multfile">
    <input id="multfile" type="file" multiple="multiple" style="display:none"
        onchange="$('#multfile-label').html(
            (this.files.length == 1) ? this.files[0].name : this.files.length + ' files');
            $(this).parent().addClass('btn-success')">
    <span id="multfile-label">Files&hellip;</span>
</label>

enter image description here

Dwaindwaine answered 5/10, 2017 at 21:3 Comment(0)
R
4

this is the best file upload style I like:

<div class="fileupload fileupload-new" data-provides="fileupload">
  <div class="input-append">
    <div class="uneditable-input span3"><i class="icon-file fileupload-exists"></i> <span class="fileupload-preview"></span></div><span class="btn btn-file"><span class="fileupload-new">Select file</span><span class="fileupload-exists">Change</span><input type="file" /></span><a href="#" class="btn fileupload-exists" data-dismiss="fileupload">Remove</a>
  </div>
</div>

you can get demo and more styles at:

http://www.jasny.net/bootstrap/javascript/#fileinput

but using this, you should replace twitter bootstrap with jasny bootstrap files..

regards.

Ragged answered 11/3, 2013 at 16:14 Comment(0)
E
4

I have Created a Custom upload button to accept only images, which can be modified as per your requirement.

Hope this helps!! :)

(Used Bootstrap framework)

Codepen-link

HTML

<center>
 <br />
 <br />
 <span class="head">Upload Button Re-Imagined</span>
 <br />
 <br />
 <div class="fileUpload blue-btn btn width100">
   <span>Upload your Organizations logo</span>
   <input type="file" class="uploadlogo" />
 </div>
</center>

CSS

 .head {
   font-size: 25px;
   font-weight: 200;
 }

 .blue-btn:hover,
 .blue-btn:active,
 .blue-btn:focus,
 .blue-btn {
   background: transparent;
   border: solid 1px #27a9e0;
   border-radius: 3px;
   color: #27a9e0;
   font-size: 16px;
   margin-bottom: 20px;
   outline: none !important;
   padding: 10px 20px;
 }

 .fileUpload {
   position: relative;
   overflow: hidden;
   height: 43px;
   margin-top: 0;
 }

 .fileUpload input.uploadlogo {
   position: absolute;
   top: 0;
   right: 0;
   margin: 0;
   padding: 0;
   font-size: 20px;
   cursor: pointer;
   opacity: 0;
   filter: alpha(opacity=0);
   width: 100%;
   height: 42px;
 }


 /*Chrome fix*/

 input::-webkit-file-upload-button {
   cursor: pointer !important;
 }

JS

// You can modify the upload files to pdf's, docs etc
//Currently it will upload only images
$(document).ready(function($) {

  // Upload btn
  $(".uploadlogo").change(function() {
    readURL(this);
  });

  function readURL(input) {
    var url = input.value;
    var ext = url.substring(url.lastIndexOf('.') + 1).toLowerCase();
    if (input.files && input.files[0] && (ext == "png" || ext == "jpeg" || ext == "jpg" || ext == "gif" || ext == "svg")) {
      var path = $('.uploadlogo').val();
      var filename = path.replace(/^.*\\/, "");
      $('.fileUpload span').html('Uploaded logo : ' + filename);
      // console.log(filename);
    } else {
      $(".uploadlogo").val("");
      $('.fileUpload span').html('Only Images Are Allowed!');
    }
  }
});
Eakin answered 11/5, 2016 at 8:19 Comment(0)
O
4

Based on the absolutely brilliant @claviska solution, to whom all the credit is owed.

Full featured Bootstrap 4 file input with validation and help text.

Based on the input group example we have a dummy input text field used for displaying the filename to the user, which gets populated from the onchange event on the actual input file field hidden behind the label button. Aside from including the bootstrap 4 validation support we've also made it possible to click anywhere on the input to open the file dialog.

Three states of the file input

The three possible states are un-validated, valid and invalid with the dummy html input tag attribute required set.

enter image description here

Html markup for the input

We introduce only 2 custom classes input-file-dummy and input-file-btn to properly style and wire the desired behaviour. Everything else is standard Bootstrap 4 markup.

<div class="input-group">
  <input type="text" class="form-control input-file-dummy" placeholder="Choose file" aria-describedby="fileHelp" required>
  <div class="valid-feedback order-last">File is valid</div>
  <div class="invalid-feedback order-last">File is required</div>
  <label class="input-group-append mb-0">
    <span class="btn btn-primary input-file-btn">
      Browse… <input type="file" hidden>
    </span>
  </label>
</div>
<small id="fileHelp" class="form-text text-muted">Choose any file you like</small>

JavaScript behavioural provisions

The dummy input needs to be read only, as per the original example, to prevent the user from changing the input which may only be changed via the open file dialog. Unfortunately validation does not occur on readonly fields so we toggle the editability of the input on focus and blur ( jquery events onfocusin and onfocusout) and ensure that it becomes validatable again once a file is selected.

Aside from also making the text field clickable, by triggering the button's click event, the rest of the functionality of populating the dummy field was envisioned by @claviska.

$(function () {
  $('.input-file-dummy').each(function () {
    $($(this).parent().find('.input-file-btn input')).on('change', {dummy: this}, function(ev) {
      $(ev.data.dummy)
        .val($(this).val().replace(/\\/g, '/').replace(/.*\//, ''))
        .trigger('focusout');
    });
    $(this).on('focusin', function () {
        $(this).attr('readonly', '');
      }).on('focusout', function () {
        $(this).removeAttr('readonly');
      }).on('click', function () {
        $(this).parent().find('.input-file-btn').click();
      });
  });
});

Custom style tweaks

Most importantly we don't want the readonly field to jump between grey background and white so we ensure it stays white. The span button doesn't have a pointer cursor but we need to add one for the input anyway.

.input-file-dummy, .input-file-btn {
  cursor: pointer;
}
.input-file-dummy[readonly] {
  background-color: white;
}

nJoy!

Ocampo answered 21/3, 2019 at 2:36 Comment(0)
M
3

I use http://gregpike.net/demos/bootstrap-file-input/demo.html:

$('input[type=file]').bootstrapFileInput();

or

$('.file-inputs').bootstrapFileInput();
Marje answered 7/5, 2014 at 20:34 Comment(1)
Use comments for tiny answers or suggestions.Chloramine
T
3

I thought I'd add my threepence worth, just to say how the default .custom-file-label and custom-file-input BS4 file input and how that can be used.

The latter class is on the input group and is not visible. While the former is the visible label and has a :after pseudoelement that looks like a button.

<div class="custom-file">
<input type="file" class="custom-file-input" id="upload">
<label class="custom-file-label" for="upload">Choose file</label>
</div>

You cannot add classes to psuedoelements, but you can style them in CSS (or SASS).

.custom-file-label:after {
    color: #fff;
    background-color: #1e7e34;
    border-color: #1c7430;
    pointer: cursor;
}
Tern answered 20/12, 2018 at 11:42 Comment(0)
S
2

/* * Bootstrap 3 filestyle * http://dev.tudosobreweb.com.br/bootstrap-filestyle/ * * Copyright (c) 2013 Markus Vinicius da Silva Lima * Update bootstrap 3 by Paulo Henrique Foxer * Version 2.0.0 * Licensed under the MIT license. * */

(function ($) {
"use strict";

var Filestyle = function (element, options) {
    this.options = options;
    this.$elementFilestyle = [];
    this.$element = $(element);
};

Filestyle.prototype = {
    clear: function () {
        this.$element.val('');
        this.$elementFilestyle.find(':text').val('');
    },

    destroy: function () {
        this.$element
            .removeAttr('style')
            .removeData('filestyle')
            .val('');
        this.$elementFilestyle.remove();
    },

    icon: function (value) {
        if (value === true) {
            if (!this.options.icon) {
                this.options.icon = true;
                this.$elementFilestyle.find('label').prepend(this.htmlIcon());
            }
        } else if (value === false) {
            if (this.options.icon) {
                this.options.icon = false;
                this.$elementFilestyle.find('i').remove();
            }
        } else {
            return this.options.icon;
        }
    },

    input: function (value) {
        if (value === true) {
            if (!this.options.input) {
                this.options.input = true;
                this.$elementFilestyle.prepend(this.htmlInput());

                var content = '',
                    files = [];
                if (this.$element[0].files === undefined) {
                    files[0] = {'name': this.$element[0].value};
                } else {
                    files = this.$element[0].files;
                }

                for (var i = 0; i < files.length; i++) {
                    content += files[i].name.split("\\").pop() + ', ';
                }
                if (content !== '') {
                    this.$elementFilestyle.find(':text').val(content.replace(/\, $/g, ''));
                }
            }
        } else if (value === false) {
            if (this.options.input) {
                this.options.input = false;
                this.$elementFilestyle.find(':text').remove();
            }
        } else {
            return this.options.input;
        }
    },

    buttonText: function (value) {
        if (value !== undefined) {
            this.options.buttonText = value;
            this.$elementFilestyle.find('label span').html(this.options.buttonText);
        } else {
            return this.options.buttonText;
        }
    },

    classButton: function (value) {
        if (value !== undefined) {
            this.options.classButton = value;
            this.$elementFilestyle.find('label').attr({'class': this.options.classButton});
            if (this.options.classButton.search(/btn-inverse|btn-primary|btn-danger|btn-warning|btn-success/i) !== -1) {
                this.$elementFilestyle.find('label i').addClass('icon-white');
            } else {
                this.$elementFilestyle.find('label i').removeClass('icon-white');
            }
        } else {
            return this.options.classButton;
        }
    },

    classIcon: function (value) {
        if (value !== undefined) {
            this.options.classIcon = value;
            if (this.options.classButton.search(/btn-inverse|btn-primary|btn-danger|btn-warning|btn-success/i) !== -1) {
                this.$elementFilestyle.find('label').find('i').attr({'class': 'icon-white '+this.options.classIcon});
            } else {
                this.$elementFilestyle.find('label').find('i').attr({'class': this.options.classIcon});
            }
        } else {
            return this.options.classIcon;
        }
    },

    classInput: function (value) {
        if (value !== undefined) {
            this.options.classInput = value;
            this.$elementFilestyle.find(':text').addClass(this.options.classInput);
        } else {
            return this.options.classInput;
        }
    },

    htmlIcon: function () {
        if (this.options.icon) {
            var colorIcon = '';
            if (this.options.classButton.search(/btn-inverse|btn-primary|btn-danger|btn-warning|btn-success/i) !== -1) {
                colorIcon = ' icon-white ';
            }

            return '<i class="'+colorIcon+this.options.classIcon+'"></i> ';
        } else {
            return '';
        }
    },

    htmlInput: function () {
        if (this.options.input) {
            return '<input type="text" class="'+this.options.classInput+'" style="width: '+this.options.inputWidthPorcent+'% !important;display: inline !important;" disabled> ';
        } else {
            return '';
        }
    },

    constructor: function () {
        var _self = this,
            html = '',
            id = this.$element.attr('id'),
            files = [];

        if (id === '' || !id) {
            id = 'filestyle-'+$('.bootstrap-filestyle').length;
            this.$element.attr({'id': id});
        }

        html = this.htmlInput()+
             '<label for="'+id+'" class="'+this.options.classButton+'">'+
                this.htmlIcon()+
                '<span>'+this.options.buttonText+'</span>'+
             '</label>';

        this.$elementFilestyle = $('<div class="bootstrap-filestyle" style="display: inline;">'+html+'</div>');

        var $label = this.$elementFilestyle.find('label');
        var $labelFocusableContainer = $label.parent();

        $labelFocusableContainer
            .attr('tabindex', "0")
            .keypress(function(e) {
                if (e.keyCode === 13 || e.charCode === 32) {
                    $label.click();
                }
            });

        // hidding input file and add filestyle
        this.$element
            .css({'position':'absolute','left':'-9999px'})
            .attr('tabindex', "-1")
            .after(this.$elementFilestyle);

        // Getting input file value
        this.$element.change(function () {
            var content = '';
            if (this.files === undefined) {
                files[0] = {'name': this.value};
            } else {
                files = this.files;
            }

            for (var i = 0; i < files.length; i++) {
                content += files[i].name.split("\\").pop() + ', ';
            }

            if (content !== '') {
                _self.$elementFilestyle.find(':text').val(content.replace(/\, $/g, ''));
            }
        });

        // Check if browser is Firefox
        if (window.navigator.userAgent.search(/firefox/i) > -1) {
            // Simulating choose file for firefox
            this.$elementFilestyle.find('label').click(function () {
                _self.$element.click();
                return false;
            });
        }
    }
};

var old = $.fn.filestyle;

$.fn.filestyle = function (option, value) {
    var get = '',
        element = this.each(function () {
            if ($(this).attr('type') === 'file') {
                var $this = $(this),
                    data = $this.data('filestyle'),
                    options = $.extend({}, $.fn.filestyle.defaults, option, typeof option === 'object' && option);

                if (!data) {
                    $this.data('filestyle', (data = new Filestyle(this, options)));
                    data.constructor();
                }

                if (typeof option === 'string') {
                    get = data[option](value);
                }
            }
        });

    if (typeof get !== undefined) {
        return get;
    } else {
        return element;
    }
};

$.fn.filestyle.defaults = {
    'buttonText': 'Escolher arquivo',
    'input': true,
    'icon': true,
    'inputWidthPorcent': 65,
    'classButton': 'btn btn-primary',
    'classInput': 'form-control file-input-button',
    'classIcon': 'icon-folder-open'
};

$.fn.filestyle.noConflict = function () {
    $.fn.filestyle = old;
    return this;
};

// Data attributes register
$('.filestyle').each(function () {
    var $this = $(this),
        options = {
            'buttonText': $this.attr('data-buttonText'),
            'input': $this.attr('data-input') === 'false' ? false : true,
            'icon': $this.attr('data-icon') === 'false' ? false : true,
            'classButton': $this.attr('data-classButton'),
            'classInput': $this.attr('data-classInput'),
            'classIcon': $this.attr('data-classIcon')
        };

    $this.filestyle(options);
});
})(window.jQuery);
Scrimmage answered 27/12, 2013 at 19:29 Comment(0)
B
2

I modified @claviska answer and works as i like (Bootstrap 3, 4 not tested):

<label class="btn btn-default">
    <span>Browse</span>
    <input type="file" style="display: none;" onchange="$(this).prev('span').text($(this).val()!=''?$(this).val():'Browse')">
</label>
Byway answered 29/9, 2016 at 6:55 Comment(0)
A
2

enter image description here

The following code makes as above the picture

Html

<form>
<div class="row">
<div class="col-lg-6">
<label for="file">
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Browse</button>
</span>
<input type="text" class="form-control" id="info" readonly="" style="background: #fff;" placeholder="Search for...">
</div><!-- /input-group -->
</label>
</div><!-- /.col-lg-6 -->
</div>

</div>
<input type="file" style="display: none;" onchange="$('#info').val($(this).val().split(/[\\|/]/).pop()); " name="file" id="file">
</form>

Javascript

<script type="text/javascript">

$(function() {
    $("label[for=file]").click(function(event) {
        event.preventDefault();
        $("#file").click();
    });
});

</script>
Auscultate answered 31/12, 2016 at 5:56 Comment(0)
M
1

I have the same problem, and i try it like this.

<div>
<button type='button' class='btn btn-info btn-file'>Browse</button>
<input type='file' name='image'/>
</div>

The CSS

<style>
.btn-file {
    position:absolute;
}
</style>

The JS

<script>
$(document).ready(function(){
    $('.btn-file').click(function(){
        $('input[name="image"]').click();
    });
});
</script>

Note : The button .btn-file must in the same tag as the input file

Hope you found the best solution...

Martinic answered 27/3, 2014 at 8:12 Comment(0)
L
1

Try following in the Bootstrap v.3.3.4

<div>
    <input id="uplFile" type="file" style="display: none;">

    <div class="input-group" style="width: 300px;">
        <div  id="btnBrowse"  class="btn btn-default input-group-addon">Select a file...</div>
        <span id="photoCover" class="form-control">
    </div>
</div>

<script type="text/javascript">
    $('#uplFile').change(function() {
        $('#photoCover').text($(this).val());
    });

    $('#btnBrowse').click(function(){
        $('#uplFile').click();
    });
</script>
Listing answered 13/4, 2015 at 22:8 Comment(0)
R
1

Here is alternate trick, it's not the best solution but it just give you a choice

HTML code:

<button clss="btn btn-primary" id="btn_upload">Choose File</button>
<input id="fileupload" class="hide" type="file" name="files[]">

Javascript:

$("#btn_upload").click(function(e){
e.preventDefault();
$("#fileupload").trigger('click');
});
Rajiv answered 2/11, 2015 at 11:47 Comment(0)
S
1

In respect of claviska answer - if you want to show uploaded file name in a basic file upload you can do it in inputs' onchange event. Just use this code:

 <label class="btn btn-default">
                    Browse...
                    <span id="uploaded-file-name" style="font-style: italic"></span>
                    <input id="file-upload" type="file" name="file"
                           onchange="$('#uploaded-file-name').text($('#file-upload')[0].value);" hidden>
 </label>

This jquery JS code is responsible will retrieving uploaded file name:

$('#file-upload')[0].value

Or with vanilla JS:

document.getElementById("file-upload").value

example

Slake answered 16/8, 2018 at 12:37 Comment(0)
H
0

No fancy shiz required:

HTML:

<form method="post" action="/api/admin/image" enctype="multipart/form-data">
    <input type="hidden" name="url" value="<%= boxes[i].url %>" />
    <input class="image-file-chosen" type="text" />
    <br />
    <input class="btn image-file-button" value="Choose Image" />
    <input class="image-file hide" type="file" name="image"/> <!-- Hidden -->
    <br />
    <br />
    <input class="btn" type="submit" name="image" value="Upload" />
    <br />
</form>

JS:

$('.image-file-button').each(function() {
      $(this).off('click').on('click', function() {
           $(this).siblings('.image-file').trigger('click');
      });
});
$('.image-file').each(function() {
      $(this).change(function () {
           $(this).siblings('.image-file-chosen').val(this.files[0].name);
      });
});

CAUTION: The three form elements in question MUST be siblings of each other (.image-file-chosen, .image-file-button, .image-file)

Hurtado answered 21/3, 2013 at 16:52 Comment(0)
P
0

In any on is interested, the accepted answer is not handling key board navigation. You shall add some js.

Here is my implementation, I added feedback for input file name and size selected.

This is a laravel blade implementation (ignore remove '{{}}' and @ instructions)

<div class="col-12 col-md-4 py-2">
    <div class="mb-3">
        <label class="btn btn-lg btn-tertiary f-intro-head-b-base px-3 py-2" id="fileAddon" for="file"
            role="button" tabindex="0">
            {{ __('Ajouter une piéce jointe') }}
            <input class="d-none mx-auto" id="file" name="file" type="file"
                value="{{ old('file') }}" aria-label="{{ __('validation.custom.attachment') }}" required />
        </label>
        <div class="mb-3">
            <input class="form-control text-bg-primary text-truncate my-2 border-0" id="fileDescription"
                type="text" aria-describedby="file" aria-label="Upload"
                @if ($errors->has('file')) is-invalid @endif disabled>
        </div>
        @push('scripts')
            <script nonce="{{ $nonce }}">
                document.addEventListener('DOMContentLoaded', function() {
                    const UNITS = [
                        "byte",
                        "kilobyte",
                        "megabyte",
                        "gigabyte",
                        "terabyte",
                        "petabyte",
                    ];
                    const BYTES_PER_KB = 1024;
                    const humanFileSize = (sizeBytes) => {
                        let size = Math.abs(Number(sizeBytes));

                        let u = 0;
                        while (size >= BYTES_PER_KB && u < UNITS.length - 1) {
                            size /= BYTES_PER_KB;
                            ++u;
                        }

                        return new Intl.NumberFormat([], {
                            style: "unit",
                            unit: UNITS[u],
                            unitDisplay: "short",
                            maximumFractionDigits: 1,
                        }).format(size);
                    };

                    const inputLabelBtn = document.getElementById('fileAddon');
                    const input = document.getElementById('file');
                    // Keyboard navigation
                    inputLabelBtn.addEventListener('keyup', (e) => {
                        if (e.keyCode === 32) {
                            document.getElementById('file').click()
                        }
                    });
                    // Get input change name and size
                    input.addEventListener('change', function() {
                        const file = this.files[0];
                        document.getElementById('fileDescription').value = `${humanFileSize(file.size)} ${file.name}`;
                    })
                });
            </script>
        @endpush
    </div>
    @foreach ($errors->get('file') as $message)
        <div class="invalid-feedback">{{ $message }}</div>
    @endforeach
</div>
Philoctetes answered 8/11, 2023 at 16:6 Comment(0)
T
-1

http://markusslima.github.io/bootstrap-filestyle/

$(":file").filestyle();

OR

<input type="file" class="filestyle" data-input="false">
Traylor answered 4/9, 2013 at 16:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.