きっかけ
file_fieldのデザインをデフォルトのものから変更したいと思いましたが、
UIkitでは単数のfile_fieldのclassは用意されているものの、
複数用のfile_fieldは用意されていなかったので、
自分で変更する方法を調べて変更してみました。
初学者のため、誤りがありましたらご指導いただけると幸いです。
環境
Rails7.1
UIkit
ActiveStorage
stimulus
前提として
すでにmodelやdb等は作成してあるとして進めさせていただきます。
完成系のイメージ
file選択ボタンの部分をデフォルトから

少しUIkitのデザインに寄せた感じにします。
実装
要点としては、下記になります。
-
file_fieldにdisplay: none;を設定する (class: 'hidden'で設定) -
file_fieldをlabelで囲み、labelのclassでcssをあてる -
file_fieldに表示したい文字はlabelとfile_fieldの間に記載する
<%= form_with(model: @photo, url: photos_path, local: true) do |f| %>
<label class='file_field'>
<span class="ml-5">画像を選択する</span>
<%= f.file_field :images, multiple: true, class: 'hidden'%>
</label>
<div class='uk-margin'>
<%= f.submit '保存', class: 'uk-button uk-button-default' %>
</div>
<% end %>
file_fieldのボタンの中に表示する文字はspanで囲った部分になっています。
参考にさせていただいたサイトでは、file_fieldにclass: 'hidden'を設定すると
デフォルトのデザインは消えるとあったのですが、
私の場合Tailwindを使用していなかったから?か消えなかったため、cssにhiddenを設定します。
また、新しく充てたいデザインはclass='file_field'としてcssに記載しています。
.hidden {
display: none !important;
}
.file_field {
background-color: rgb(253, 253, 253);
border: 1px solid #ced4da;
border-radius: 0.25rem;
padding: 0.75rem 1rem;
}
.file_field:hover {
border-color: #80858b;
}
display: noneだけでも消えたのですが、もし消えないようなら!importantもつけてみてください
!importantをつけるとスタイルの宣言の優先度を上げて適用されます。
file_fieldとhoverについては、UIkitでの送信ボタンの方にデザインを寄せた感じです。
javascriptで選択したfile数を表示する
上記の設定までで完成系のイメージのボタンにはなり、送信もできますが、
このままだとファイルを選択した後も「画像を選択する」が表示されていて、
ユーザーが本当に選択されたのか?と戸惑ってしまいます。
file_fieldアイコン内の文字を選択した数を表示できるようにします。
追加する部分
- 選択された画像数を取得するjsを
photo_contoroller.jsで定義する -
photo_controller.jsをlabel部分で適用する -
new.html.erbのspanとfile_fieldにjsで定義したtargetを記載する
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["fileField", "fileLabel"]
connect() {
this.fileFieldTarget.addEventListener('change', this.updateFileLabel.bind(this));
}
disconnect() {
this.fileFieldTarget.removeEventListener('change', this.updateFileLabel.bind(this));
}
updateFileLabel() {
let selectedFileCount = this.fileFieldTarget.files.length;
this.fileLabelTarget.textContent = selectedFileCount + " 個の画像を選択しています";
}
}
fileFieldtargetをhtmlのformのfile_fieldに設定し、file_fieldでファイルが選択されたら、
chengeイベントが発生し、updateFileLabel()が実行されます。
updateFileLabel()では、選択されたファイル数(length)を取得して、表示する文字を組み、fileLabelをtargetで設定したhtmlの部分の文字が変更されます。
<%= form_with(model: @photo, url: photos_path, local: true) do |f| %>
<%# 変更箇所 data-controller='photo'とすることでphoto_controller.jsの内容が使える %>
<label class='file_field' data-controller='photo'>
<%# 変更箇所 表示文字を変える部分にfileLabel targetを設定 %>
<%# 画像を選択する の部分はデフォルトとして表示される %>
<span class='ml-5' data-photo-target='fileLabel'>画像を選択する</span>
<%# 変更箇所 ファイル数のchangeをチェックする部分にfileField targetを設定 %>
<%= f.file_field :images, multiple: true, class: 'hidden', data: { photo_target: 'fileField' } %>
</label>
<div class='uk-margin'>
<%= f.submit '保存', class: 'uk-button uk-button-default' %>
</div>
<% end %>
デザイン変更の手順は以上となります。
参考

