{"action":"created","issue":{"url":"https://api.github.com/repos/twbs/bootstrap/issues/20813","repository_url":"https://api.github.com/repos/twbs/bootstrap","labels_url":"https://api.github.com/repos/twbs/bootstrap/issues/20813/labels{/name}","comments_url":"https://api.github.com/repos/twbs/bootstrap/issues/20813/comments","events_url":"https://api.github.com/repos/twbs/bootstrap/issues/20813/events","html_url":"https://github.com/twbs/bootstrap/issues/20813","id":180277709,"number":20813,"title":"v4 Custom File Input Dynamic \"Choose file...\" ::after pseudo selector","user":{"login":"niftylettuce","id":523141,"avatar_url":"https://avatars.githubusercontent.com/u/523141?v=3","gravatar_id":"","url":"https://api.github.com/users/niftylettuce","html_url":"https://github.com/niftylettuce","followers_url":"https://api.github.com/users/niftylettuce/followers","following_url":"https://api.github.com/users/niftylettuce/following{/other_user}","gists_url":"https://api.github.com/users/niftylettuce/gists{/gist_id}","starred_url":"https://api.github.com/users/niftylettuce/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/niftylettuce/subscriptions","organizations_url":"https://api.github.com/users/niftylettuce/orgs","repos_url":"https://api.github.com/users/niftylettuce/repos","events_url":"https://api.github.com/users/niftylettuce/events{/privacy}","received_events_url":"https://api.github.com/users/niftylettuce/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-09-30T11:04:16Z","updated_at":"2016-11-28T04:23:47Z","closed_at":null,"body":"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.\n## Example Screenshots:\n\n> Before input is selected:\n\n![screencapture-localhost-3000-jobs-create-1475233192329](https://cloud.githubusercontent.com/assets/523141/18989802/e9d99a70-86db-11e6-9bf1-7bc616a1dfa0.png)\n\n> After input is selected:\n\n![screencapture-localhost-3000-jobs-create-1475233212895](https://cloud.githubusercontent.com/assets/523141/18989805/ee0904c8-86db-11e6-9107-a91b90359495.png)\n## Usage\n\n> JavaScript:\n\n``` js\n    // handle custom file inputs\n    $('body').on('change', 'input[type=\"file\"][data-toggle=\"custom-file\"]', function (ev) {\n\n      const $input = $(this);\n      const target = $input.data('target');\n      const $target = $(target);\n\n      if (!$target.length)\n        return console.error('Invalid target for custom file', $input);\n\n      if (!$target.attr('data-content'))\n        return console.error('Invalid `data-content` for custom file target', $input);\n\n      // set original content so we can revert if user deselects file\n      if (!$target.attr('data-original-content'))\n        $target.attr('data-original-content', $target.attr('data-content'));\n\n      const input = $input.get(0);\n\n      let name = _.isObject(input)\n        && _.isObject(input.files)\n        && _.isObject(input.files[0])\n        && _.isString(input.files[0].name) ? input.files[0].name : $input.val();\n\n      if (_.isNull(name) || name === '')\n        name = $target.attr('data-original-content');\n\n      $target.attr('data-content', name);\n\n    });\n```\n\n> HTML:\n\n``` html\n          <label class=\"custom-file d-block\">\n            <input data-toggle=\"custom-file\" data-target=\"#company-logo\" type=\"file\" name=\"company_logo\" accept=\"image/png\" class=\"custom-file-input\">\n            <span id=\"company-logo\" class=\"custom-file-control custom-file-name\" data-content=\"Upload company logo...\"></span>\n          </label>\n```\n\n> CSS:\n\n``` scss\n// support custom file inputs\n.custom-file-name:after {\n  content: attr(data-content) !important;\n  position: absolute;\n  top: 0px;\n  left: 0px;\n  display: block;\n  height: 100%;\n  overflow: hidden;\n  padding: 0.5rem 1rem;\n}\n```\n"},"comment":{"url":"https://api.github.com/repos/twbs/bootstrap/issues/comments/263180800","html_url":"https://github.com/twbs/bootstrap/issues/20813#issuecomment-263180800","issue_url":"https://api.github.com/repos/twbs/bootstrap/issues/20813","id":263180800,"user":{"login":"bardiharborow","id":1073681,"avatar_url":"https://avatars.githubusercontent.com/u/1073681?v=3","gravatar_id":"","url":"https://api.github.com/users/bardiharborow","html_url":"https://github.com/bardiharborow","followers_url":"https://api.github.com/users/bardiharborow/followers","following_url":"https://api.github.com/users/bardiharborow/following{/other_user}","gists_url":"https://api.github.com/users/bardiharborow/gists{/gist_id}","starred_url":"https://api.github.com/users/bardiharborow/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bardiharborow/subscriptions","organizations_url":"https://api.github.com/users/bardiharborow/orgs","repos_url":"https://api.github.com/users/bardiharborow/repos","events_url":"https://api.github.com/users/bardiharborow/events{/privacy}","received_events_url":"https://api.github.com/users/bardiharborow/received_events","type":"User","site_admin":false},"created_at":"2016-11-28T04:23:47Z","updated_at":"2016-11-28T04:23:47Z","body":"Related: #17269."}}
{"actor":{"display_login":"bardiharborow"}}