Bootstrap のファイル選択を custom-file-input できれいにする

f:id:Naotsugu:20191118210241p:plain


はじめに

Bootstrap の Forms コンポーネントは、デフォルトだと file input だけ統一感がなく残念な感じです。

custom-file-input を使って以下のような file input を作る手順を見ていきます。

f:id:Naotsugu:20191118195752p:plain

なお、ここでは Bootstrap 4 を使います。


テンプレート

以下のような html を出発点とします。

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <style>
      .container {
        margin: 50px;
      }
    </style>
</head>
  <body>
    <div class="container">

    </div>
  </body>
</html>


<div class="container"> の中にフォームを作成していきましょう。


デフォルトの ファイル インプット

最初にデフォルトの file input を見てみましょう。

デフォルトの file input は form-control-file クラスを使います。

以下のフォームを定義します。

<form>

  <div class="form-group">
    <label for="inputText">Input text</label>
    <input type="text" class="form-control" id="inputText" placeholder="Input text">
  </div>

  <div class="form-group">
    <label for="inputFile">File input</label>
    <input type="file" class="form-control-file" id="inputFile">
  </div>

  <hr/>

  <button type="submit" class="btn btn-primary">Submit</button>

</form>


ブラウザ標準のファイル選択が使われるだけで、以下のようになります。

f:id:Naotsugu:20191117182505p:plain


カスタム・ファイル・インプット

Bootstrap 4 では、custom-file が用意されているので、これを使ってみましょう。

custom-file の中に custom-file-input と、custom-file-label を定義します。

  <div class="form-group">
    <label for="inputFile">File input</label>
    <div class="custom-file">
      <input type="file" class="custom-file-input" id="inputFile">
      <label class="custom-file-label" for="inputFile">Choose file</label>
    </div>
  </div>


以下のようになります。

f:id:Naotsugu:20191117182803p:plain


bs-custom-file-input を使う

custom-file で見た目は変わりましたが、このままではファイル選択してもファイル名が表示されません。

input 要素の onchange イベントでラベル名を変えてあげないといけないのですが、以下のスクリプトを導入することで簡単に対応できます。

GitHub - Johann-S/bs-custom-file-input: A little plugin for Bootstrap 4 custom file input


今回は CDN から取得します。</body> タグの直前に以下のコードを追加します。

<script src="https://cdn.jsdelivr.net/npm/bs-custom-file-input/dist/bs-custom-file-input.js"></script>
<script>
  bsCustomFileInput.init();
</script>
</body>
</html>


bsCustomFileInput.init() を呼んで初期化することで、フォームの reset と、input の change イベントにリスナが追加され、ファイル選択で選択したファイルが表示されるようになります。

f:id:Naotsugu:20191117183034p:plain


ラベルの変更

Browse というラベルは data-browse で変更できます(SCSS でカスタマイズすることももちろんできます)。

bs-custom-file-input を使えば、ファイルのドロップにも対応しているので、ラベル値も合わせて変更しましょう。

  <div class="form-group">
    <label for="inputFile">File input</label>
    <div class="custom-file">
      <input type="file" class="custom-file-input" id="inputFile">
      <label class="custom-file-label" for="inputFile" data-browse="参照">ファイルを選択(ここにドロップすることもできます)</label>
    </div>
  </div>


以下のようになりました。

f:id:Naotsugu:20191117183152p:plain


取消ボタン

ファイル選択を取り消すための 取消ボタンも付けましょう。

form-group で括って、input-group-append で取消ボタンを追加します。

  <div class="form-group">
    <label for="inputFile">File input</label>
    <div class="input-group">
      <div class="custom-file">
        <input type="file" class="custom-file-input" id="inputFile">
        <label class="custom-file-label" for="inputFile" data-browse="参照">ファイルを選択(ここにドロップすることもできます)</label>
      </div>
      <div class="input-group-append">
        <button type="button" class="btn btn-outline-secondary input-group-text" id="inputFileReset">取消</button>
      </div>
    </div>
  </div>


取消ボタンのクリック時の処理は以下のようにします。

<script>
  bsCustomFileInput.init();
  document.getElementById('inputFileReset').addEventListener('click', function() {
    var elem = document.getElementById('inputFile');
    elem.value = '';
    elem.dispatchEvent(new Event('change'));
  });
</script>

取消ボタン押下で file input の value を空にしています。

これだけだとファイル名のラベルが残ってしまうため、change イベントを発行して bs-custom-file-input にファイル名を更新してもらいます。

f:id:Naotsugu:20191117200052g:plain


取消イベントのマルチブラウザ化

先ほどの例では、file input の value を空に設定していましたが、IE などの古いブラウザでは動きません。

基本的には、file input の value 値の書き換えはセキュリティ上の制約で行うことができません。 ただし、空値への更新は大抵のブラウザで可能です( IE11 以前や Opera は不可)。

form の reset を行えば空にすることはできますが、その他のフォーム要素の値がすべてクリアされてしまうため、良くあるワークアラウンドが、要素を clone する方法で、以下のようになります。

<script>
  bsCustomFileInput.init();

  document.getElementById('inputFileReset').addEventListener('click', function() {

    bsCustomFileInput.destroy();

    var elem = document.getElementById('inputFile');
    elem.value = '';
    var clone = elem.cloneNode(false);
    elem.parentNode.replaceChild(clone, elem);

    bsCustomFileInput.init();

  });
</script>


手元に環境がないため試せていませんが、多分これで大丈夫ではないかと思います。


まとめ

Bootstrap4 で カスタム・ファイル・インプット の使い方を見てきました。

取消ボタン含め、以下のような統一感のある UI ができました。

f:id:Naotsugu:20191117184429p:plain


最後に、ここで使ったファイルの全体像を示して終わりたいと思います。

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
  <style>
    .container {
      margin: 50px;
    }
  </style>
</head>
<body>
<div class="container">

<form>
  <div class="form-group">
    <label for="inputText">Input text</label>
    <input type="text" class="form-control" id="inputText" placeholder="Input text">
  </div>
  <div class="form-group">
    <label for="inputFile">File input</label>
    <div class="input-group">
      <div class="custom-file">
        <input type="file" class="custom-file-input" id="inputFile">
        <label class="custom-file-label" for="inputFile" data-browse="参照">ファイルを選択(ここにドロップすることもできます)</label>
      </div>
      <div class="input-group-append">
        <button type="button" class="btn btn-outline-secondary input-group-text" id="inputFileReset">取消</button>
      </div>
    </div>
  </div>
  <hr/>
  <button type="submit" class="btn btn-primary">Submit</button>
</form>

</div>

<script src="https://cdn.jsdelivr.net/npm/bs-custom-file-input/dist/bs-custom-file-input.js"></script>
<script>
  bsCustomFileInput.init();

  document.getElementById('inputFileReset').addEventListener('click', function() {

    bsCustomFileInput.destroy();

    var elem = document.getElementById('inputFile');
    elem.value = '';
    var clone = elem.cloneNode(false);
    elem.parentNode.replaceChild(clone, elem);

    bsCustomFileInput.init();

  });
</script>
</body>
</html>



Bootstrap 4 フロントエンド開発の教科書

Bootstrap 4 フロントエンド開発の教科書

  • 作者:宮本 麻矢,朝平 文彦
  • 出版社/メーカー: 技術評論社
  • 発売日: 2018/08/25
  • メディア: 単行本(ソフトカバー)

Bootstrap4ファーストガイド―CSS設計の手間を大幅に削減!

Bootstrap4ファーストガイド―CSS設計の手間を大幅に削減!

  • 作者:相澤 裕介
  • 出版社/メーカー: カットシステム
  • 発売日: 2018/05/01
  • メディア: 単行本

CSSフレームワーク Bootstrap入門

CSSフレームワーク Bootstrap入門

  • 作者:掌田津耶乃
  • 出版社/メーカー: 秀和システム
  • 発売日: 2018/02/22
  • メディア: 単行本