コード例
ここで作るのは下記のようなUIです。
デモはこちらに用意しています。
aria-expanded
を使うのが良さそうですaria-expanded
をCSS擬似セレクタで読み取るアプローチを採用しますstyle
を変更します<div> <h2 class="text-4xl pb-8 border-b border-gray-300"> Frequently Asked Questions </h2> <%= render 'accordion_row', title: "携帯プランの変更はどうすればいいですか?" do %> 携帯プランの変更は、店頭・公式アプリ・ウェブサイトから可能です。アプリやウェブでは24時間対応しており、数分で完了します。 <% end %> <%= render 'accordion_row', title: "機種変更時のデータ移行はできますか?" do %> 機種変更時、データ移行はスタッフがサポートします。また、クラウドサービスやアプリを使えば簡単に自分で移行も可能です。 <% end %> <%= render 'accordion_row', title: "解約の手続き方法を教えてください。" do %> 解約手続きは、契約者ご本人が店頭で行う必要があります。身分証明書をご持参ください。一部プランはウェブでの手続きも可能です。 <% end %> </div>
accordion_row
partialを切っています
do end
ブロックとyield
を使って、コードをスッキリさせています。この使い方はRails Guideでも紹介されていますaccordion_row
partial<div class="py-4 border-b border-gray-300" data-controller="accordion"> <h3 class="flex justify-between text-xl cursor-pointer"> <span><%= title %></span> <button aria-expanded="false" class="aria-[expanded=true]:rotate-180 pt-2 transition-all duration-300" data-action="click->accordion#toggle"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6"> <path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5"/> </svg> </button> </h3> <div data-accordion-target="revealable" class="h-0 overflow-hidden transition-all duration-300 text-sm"> <div class="mt-4"><%= yield %></div> </div> </div>
data-controller="accordion"
となっているところで、AccordionController
Stimulus controllerに接続します<button>
のところはclass="aria-[expanded=true]:rotate-180"
がありますので、aria-expanded
属性の値によって表示が変えるCSS擬似セレクタですdata-action="click->accordion#toggle"
のところはアコーディオン開閉ボタンです
data-action="click->accordion#toggle"
は、「クリックしたらaccordion
controllerのtoggle()
メソッドを実行すること」という意味です。イベントハンドラになりますdata-accordion-target="revealable"
となっているところが、アコーディオンの開閉で見え隠れする箇所です
data-accordion-target="revealable"
なので、Stimulus controllerから制御される箇所ですhidden
で隠す訳にはいきません。h-0 overflow-hidden
で隠して、徐々に大きくなるアニメーションができるような隠し方をしていますtarget
になっていますimport {Controller} from "@hotwired/stimulus" // Connects to data-controller="accordion" export default class extends Controller { static targets = ["revealable"] connect() { } toggle(event) { event.currentTarget.ariaExpanded = event.currentTarget.ariaExpanded == "true" ? "false" : "true" this.#toggleRevealableTargets() } #toggleRevealableTargets() { this.revealableTargets.forEach(target => { /* * CSS transitions cannot transition if the destination height * is not explicitly specified (like height: auto). * Hence, we get the scrollHeight with JavaScript and * explicitly set that value as the destination height. * */ if (parseInt(target.style.height)) { target.style.height = 0 } else { const scrollHeight = target.scrollHeight target.style.height = scrollHeight + "px" } }) } }
connect() {}
メソッド定義があります。これはbin/rails g stimulus [controller名]
をやると自動的に作ってくれるもので私はそのまま残すことが多いです
alert('hello')
ってやるとcontrollerがちゃんとHTMLと繋がったことがわかりますので、Stimulusを使う第一歩で私は必ずこの確認をしていますstatic targets =
を使って、先ほどHTMLで指定したdata-accordion-target="switch"
, data-accordion-target="revealable"
と接続しますtoggle()
だけです。data-action="click->accordion#toggle"
によって呼ばれます
toggle()
が呼び出されると
<button>
のaria-expanded
属性が変化します。aria-expanded
属性はCSS擬似セレクタで監視されていますので、ボタンの表示が変化します #toggleRevealableTargets()
メソッドが呼ばれ、revealable
の表示・非表示が変わります(アニメーションの都合上,height
で制御しています) aria-expanded
に持たせていますが、アニメーションの都合上でうまくいかないところはStimulus ControllerからJavaScriptで操作していますなお今回のアクセシビリティは簡易的にやっただけですので、抜けている箇所があります。この点はご了承ください。