きっかけ
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 + " 個の画像を選択しています";
}
}
fileField
targetを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 %>
デザイン変更の手順は以上となります。
参考