question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

v4 Custom File Input Dynamic "Choose file..." ::after pseudo selector

See original GitHub issue

I thought I should share this, maybe we could make this into a JavaScript component that can be toggled. It’s a super helpful little JavaScript snippet and CSS that lets you have custom file input boxes with the “Choose file…” and “Browse” buttons, but when the user changes the file input (selects a file) it will show the file name. It should be cross-browser compatible as well. I used lodash for the _, but it could be refactored with whatever @cvrebert and @mdo would use here - I just did this pretty quickly. Hope you don’t mind the ES6 syntax.

Example Screenshots:

Before input is selected:

screencapture-localhost-3000-jobs-create-1475233192329

After input is selected:

screencapture-localhost-3000-jobs-create-1475233212895

Usage

JavaScript:

    // handle custom file inputs
    $('body').on('change', 'input[type="file"][data-toggle="custom-file"]', function (ev) {

      const $input = $(this);
      const target = $input.data('target');
      const $target = $(target);

      if (!$target.length)
        return console.error('Invalid target for custom file', $input);

      if (!$target.attr('data-content'))
        return console.error('Invalid `data-content` for custom file target', $input);

      // set original content so we can revert if user deselects file
      if (!$target.attr('data-original-content'))
        $target.attr('data-original-content', $target.attr('data-content'));

      const input = $input.get(0);

      let name = _.isObject(input)
        && _.isObject(input.files)
        && _.isObject(input.files[0])
        && _.isString(input.files[0].name) ? input.files[0].name : $input.val();

      if (_.isNull(name) || name === '')
        name = $target.attr('data-original-content');

      $target.attr('data-content', name);

    });

HTML:

          <label class="custom-file d-block">
            <input data-toggle="custom-file" data-target="#company-logo" type="file" name="company_logo" accept="image/png" class="custom-file-input">
            <span id="company-logo" class="custom-file-control custom-file-name" data-content="Upload company logo..."></span>
          </label>

CSS:

// support custom file inputs
.custom-file-name:after {
  content: attr(data-content) !important;
  position: absolute;
  top: 0px;
  left: 0px;
  display: block;
  height: 100%;
  overflow: hidden;
  padding: 0.5rem 1rem;
}

Issue Analytics

  • State:closed
  • Created 7 years ago
  • Reactions:35
  • Comments:16 (6 by maintainers)

github_iconTop GitHub Comments

23reactions
blixtcommented, Feb 16, 2018

Got bitten by this today. It’s very strange to me to support styling something into being dysfunctional.

Out of the box, following the documentation, the input box:

  • Does not show any interactivity on hover
  • Does not style focus (use keyboard to navigate form)
  • Does not have an active state (pressed)
  • Does not indicate disabled/enabled state
  • Does not show that a file was picked

When I implemented this I honestly didn’t see the notice that said you need custom JS, and when I did a second pass and did notice it I pulled in the bootstrap.min.js code because “obviously that’s what they mean”, only to find out that the documentation actually means you should implement it yourself with no additional guidance.

If this is being solved in the future, I would suggest in the meantime making the “custom JS” statement more specific and possibly a warning box to avoid this confusion.

12reactions
jmschecommented, Jun 27, 2018

Just improved @Ocoolsanni 's snippet a bit, which will handle two more cases:

  • if there are several file inputs on the page
  • if some inputs are dynamically added
$(document).on('change', '.custom-file-input', function () {
    let fileName = $(this).val().replace(/\\/g, '/').replace(/.*\//, '');
    $(this).parent('.custom-file').find('.custom-file-label').text(fileName);
});

Again, thanks @Ocoolsanni for the idea and the base snippet!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Bootstrap 4 File Input - Stack Overflow
In Bootstrap 4, the initial placeholder value is set on the custom-file-control with a CSS pseudo ::after element based on the HTML language ......
Read more >
::file-selector-button | CSS-Tricks - CSS-Tricks
The ::file-selector-button in CSS is a pseudo-element that selects in HTML. ... The file input button is located in the shadow DOM.
Read more >
Pseudo-classes - CSS: Cascading Style Sheets | MDN
A CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s). For example, the pseudo-class...
Read more >
How to get file input by selected file name without path using ...
To select the file we will use HTML <input type=”file”>. After that we will get the file name by using the jQuery change()...
Read more >
Selectors - W3C
The following table summarizes CSS 2.1 selector syntax: ... The dynamic pseudo-classes ... It matches any single element in the document tree.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found