input type="file"のボタンデザインとJavaScriptの処理方法

input type="file"はそのまま使用されない

HTMLではinput type="file"を記述すれば1つまたは複数のファイルを端末のストレージから選択できます。

<input type="file">

しかし、このまま使用するのは見た目が悪いため、ほとんどのWebサイトではCSSで装飾してJavaScriptでファイル名を処理している。

これについて解説しているWebサイトはたくさんあるが、コードが間違っているケースが多いため、iwb.jpでもボタンデザインとJavaScriptの処理方法について記載しました。

type="file"をlabelタグで囲む

最初にCSSで装飾しやすいようにlabelタグで囲む。

labelタグだとタブキーを押した際にフォーカスされないのでtabindex="0"を付ける。

type="file"はそのままだとすべてのファイルが対象になってしまうため、今回はPNGとJPEGだけを選択できるよう「accept=".png, .jpg, .jpeg"」を付けてあります。

また、複数ファイルを選択できるようmultiple属性も付けてあります。

<label class="fileUploadBtn" tabindex="0">
  <input type="file" name="file" id="file" accept=".png, .jpg, .jpeg" multiple>ファイルを選択
</label>

input type="file"は装飾の邪魔になるため、opacity: 0; で非表示にします。

あとはlabelタグの.fileUploadBtnに装飾用のCSSを適用すれば以下のような見た目のボタンの完成です。

#file {
  position: absolute;
  opacity: 0;
  width: 10px;
}
.fileUploadBtn {
  display: inline-block;
  padding: 1rem 2rem;
  background: #369;
  color: #fff;
  cursor: pointer;
}
.fileUploadBtn:hover,
.fileUploadBtn:focus {
  filter: brightness(1.2);
}

※ #fileをdisplay: none;にするとキーボード操作が不可になるためopacity: 0;で消しています。この場合、ボタンから#fileがはみ出すのでwidth: 10px;で縮小しています。(labelではなくinputタグのフォーカス時のキーボード操作のことなので視覚障害者向けの対応)

JavaScriptで選択したファイル名を表示

opacity: 0; で「input type="file"」を非表示にした影響で「選択されていません」や「選択後のファイル名」が表示されないようになっています。

そのため、JavaScriptで選択したファイル名を表示させる処理を追加する必要があります。

まず最初にファイル名を表示する要素をファイルを選択ボタンの下に表示します。

ファイル選択前は「選択されていません」と表示したいため、以下のように書きます。

<label class="fileUploadBtn" tabindex="0">
  <input type="file" name="file" id="file" accept=".png, .jpg, .jpeg" multiple>ファイルを選択
</label>
<p id="fileName">選択されていません</p>

次にファイルを選択した際にファイル名の一覧が表示されるようJavaScriptのコードを追加します。

やり方は「input type="file"」のchangeイベントの発火で名前の一覧を取得して「選択されていません (#fileName)」のところに挿入するだけです。

※ 選択されていないときは「選択されていません」を返すのを忘れずに。
※ このサンプルでは選択可能なファイル数を3つにしてあります。
※ XSS防止のためにinnerHTMLでファイル名の一覧を挿入してはいけません。

const file = document.getElementById('file');
const fileName = document.getElementById('fileName');
file.addEventListener('change', (event) => {
  const files = event.target.files;
  const fileNames = [];
  if (files.length > 3) {
    fileName.textContent = '選択可能なファイル数は3つまでです。';
    return;
  }
  for (let i = 0; i < files.length; i++) {
    fileNames.push(files[i].name);
  }
  const fileNamesList = fileNames.join('\n');
  fileName.textContent = fileNamesList ? fileNamesList : '選択されていません';
});

input type="file"のボタンデザインとJavaScriptのサンプル