115

I have a problem with the custom-file-input class in Bootstrap 4. after I chose which file I want to upload the filename do not show.

I use this code:

<div class="input-group mb-3">
  <div class="custom-file">
    <input type="file" class="custom-file-input" id="inputGroupFile02">
    <label class="custom-file-label" for="inputGroupFile02">Choose file</label>
  </div>
  <div class="input-group-append">
    <button class="btn btn-primary">Upload</button>
  </div>
</div>

Any idea how I can fix it without getting too complicated?

VDWWD
  • 35,079
  • 22
  • 62
  • 79
Terchila Marian
  • 2,225
  • 3
  • 25
  • 48

9 Answers9

148

You need to use javascript to show the name of the choosed file, as written in the documentation: https://getbootstrap.com/docs/4.5/components/forms/#file-browser

Here you can find the solution: Bootstrap 4 File Input

That's the code for your example:

<html lang="en">
    <head>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
        <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
    </head>
    <body>
        <div class="input-group mb-3">
            <div class="custom-file">
                <input type="file" class="custom-file-input" id="inputGroupFile02"/>
                <label class="custom-file-label" for="inputGroupFile02">Choose file</label>
            </div>
            <div class="input-group-append">
                <button class="btn btn-primary">Upload</button>
            </div>
        </div>
        <script>
            $('#inputGroupFile02').on('change',function(){
                //get the file name
                var fileName = $(this).val();
                //replace the "Choose a file" label
                $(this).next('.custom-file-label').html(fileName);
            })
        </script>
    </body>
</html>
yolenoyer
  • 8,797
  • 2
  • 27
  • 61
debe
  • 1,752
  • 2
  • 12
  • 11
  • Can I simply opt out of this and simply get the native file input? – Victor Oct 01 '18 at 13:53
  • 13
    this sets C:\fakepath\myfile.ext I'm on linux it is weird to see C:\... not really a good solution. – Pablo Pazos Nov 09 '18 at 18:41
  • 10
    You can manipulate the string to remove "C\fakepath" to have only the filename. `var cleanFileName = fileName.replace('C:\\fakepath\\', " ");` – adityaekawade Jan 30 '19 at 19:04
  • 5
    @adityaekawade I'd simplify this to say you can replace `var fileName = $(this).val();` with `var fileName = $(this).val().replace('C:\\fakepath\\', " ");` sound reasonable? – alexjhart Mar 05 '19 at 23:02
  • Why put an extra space? just do fileName.replace('C:\\fakepath\\', " "); – Danish Absar Sep 04 '19 at 04:42
  • 9
    You better use `e.target.files[0].name` like Anuja below. That's just giving the name without the fake path... – doekman Feb 13 '20 at 14:27
96

I have used following for the same:

<script type="application/javascript">
    $('input[type="file"]').change(function(e){
        var fileName = e.target.files[0].name;
        $('.custom-file-label').html(fileName);
    });
</script>
Anuja P
  • 2,123
  • 2
  • 19
  • 32
  • 4
    This got my 90% of the way. However I had multiple file inputs so needed to target by ID instead of class. – George Harnwell Mar 13 '19 at 15:48
  • 11
    If you have several file inputs, you can use this: `$(e.target).siblings('.custom-file-label').html(fileName);` instead – Federico G May 24 '19 at 21:01
  • 2
    You should use `.text(fileName)` instead of `.html(fileName)`. – jor Jul 12 '19 at 13:32
  • This will be good if you have only 1 file input. Multiple file input will replace all the labels with the same file name (last file you choose). – Ranch Camal Jan 06 '20 at 16:16
  • If you have label next to input and everything in one div, you can do something like: `$(e.target).parent('div').find('label').html(fileName)` – dsomnus Mar 05 '20 at 16:07
  • I found a problem: after selecting a file, if you click again on "browse files" and select another or the same file, more than one file is sent to my backend! So how do you clear any previously selected files if you click on browse files again? – Pathros Oct 26 '20 at 18:40
  • Another way to do it with multiple inputs: $(this).parent().find('.custom-file-label').html(fileName); – Chad Reitsma Apr 12 '23 at 22:08
48

The answer of Anuja Patil only works with a single file input on a page. This works if there are more than one. This snippet will also show all files if multiple is enabled.

<script type="text/javascript">

    $('.custom-file input').change(function (e) {
        var files = [];
        for (var i = 0; i < $(this)[0].files.length; i++) {
            files.push($(this)[0].files[i].name);
        }
        $(this).next('.custom-file-label').html(files.join(', '));
    });

</script>

Note that $(this).next('.custom-file-label').html($(this)[0].files.join(', ')); does not work. So that is why the for loop is needed.

If you never work with mulitple files in the file upload, this simpler snippet can be used.

<script type="text/javascript">

    $('.custom-file input').change(function (e) {
        if (e.target.files.length) {
            $(this).next('.custom-file-label').html(e.target.files[0].name);
        }
    });

</script>
VDWWD
  • 35,079
  • 22
  • 62
  • 79
  • 2
    If someone cancels out of the file upload, `e.target.files` will be empty and throw an error `Uncaught TypeError: Cannot read property 'name' of undefined`. If you check the length of `e.target.files` you can avoid the console error. Though functionally nothing is broken. – phyatt Jan 28 '20 at 16:45
  • @phyatt no it does not. At least not in Edge, Chrome and FireFox. – VDWWD Jan 28 '20 at 16:54
  • 1
    for the second simpler snippet example. The first example is fine. – phyatt Jan 28 '20 at 18:43
  • @phyatt i tried to reproduce. But there are no errors when opening the file dialog and then pressing cancel...? What browser/os are you using? – VDWWD Jan 28 '20 at 20:33
  • Chrome on MacOS. First I select a valid file and click okay to the file browser. Then I reopen the file dialog again and cancel out. I should probably make a jsfiddle to show it off. – phyatt Jan 28 '20 at 21:46
  • 2
    @phyatt, found it and fixed it. Thanks for pointing this out! – VDWWD Jan 29 '20 at 19:56
  • Also make sure to add "overflow: hidden; white-space: nowrap;" to the .custom-file-label otherwise lots of selected files will spill over down your page. – Jeff Widmer Sep 29 '20 at 14:46
35
$(document).on('change', '.custom-file-input', function (event) {
    $(this).next('.custom-file-label').html(event.target.files[0].name);
})

Best of all worlds. Works on dynamically created inputs, and uses actual file name.

stardust4891
  • 2,390
  • 1
  • 18
  • 30
10

This works with Bootstrap 4.1.3:

<script>
    $("input[type=file]").change(function () {
        var fieldVal = $(this).val();

        // Change the node's value by removing the fake path (Chrome)
        fieldVal = fieldVal.replace("C:\\fakepath\\", "");

        if (fieldVal != undefined || fieldVal != "") {
            $(this).next(".custom-file-label").attr('data-content', fieldVal);
            $(this).next(".custom-file-label").text(fieldVal);
        }
    });
</script>
kexxcream
  • 5,873
  • 8
  • 43
  • 62
6

Johann-S solution works great. (And it looks like he created the awesome plugin)

The Bootstrap 4.3 documentation example page uses this plugin to modify the filename: https://github.com/Johann-S/bs-custom-file-input

Use the Bootstrap custom file input classes. Add the plugin to your project, and add this code in your script file on the page.

$(document).ready(function () {
  bsCustomFileInput.init()
})
philyawj
  • 141
  • 2
  • 4
4

If you want you can use the recommended Bootstrap plugin to dynamize your custom file input: https://www.npmjs.com/package/bs-custom-file-input

This plugin can be use with or without jQuery and works with React an Angular

Johann-S
  • 1,181
  • 1
  • 10
  • 10
3

When you have multiple files, an idea is to show only the first file and the number of the hidden file names.

$('.custom-file input').change(function() {
    var $el = $(this),
    files = $el[0].files,
    label = files[0].name;
    if (files.length > 1) {
        label = label + " and " + String(files.length - 1) + " more files"
    }
    $el.next('.custom-file-label').html(label);
});
Vassilis
  • 2,801
  • 1
  • 20
  • 16
2

This code works for me:

<script type="application/javascript">
    $('#elementID').change(function(event){
        var fileName = event.target.files[0].name;
        if (event.target.nextElementSibling!=null){
            event.target.nextElementSibling.innerText=fileName;
        }
    });
</script>
m1ch4ls
  • 3,317
  • 18
  • 31
Jorge Santos Neill
  • 1,635
  • 13
  • 6