コード例
ここで作るのは下記のようなUIです。
2つの方法で作ります。デモはこちらです: StimulusバージョンとCheckboxバージョンです。
aria-checked
も設定しますaria-checked
をつけます:checked
を使い、CSSだけでトグルを左右に動かしたり、背景をグレイから青に変更したりしますaria-checked
をつけるだけですので、こちらを採用します<% set_breadcrumbs [["Toggle Stimulus", component_path(:toggle)]] %> <%= render 'template', title: "Toggle Stimulus", description: "Toggle implemented with Stimulus" do %> <!-- Enabled: "bg-indigo-600", Not Enabled: "bg-gray-200" --> <div class="text-center"> <button type="button" class="group bg-gray-200 aria-checked:bg-indigo-600 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus:ring-2 focus:ring-indigo-600 focus:ring-offset-2" role="switch" aria-checked="false" data-controller="switch" data-action="click->switch#toggle keydown.space:stop:prevent->switch#toggle" > <span class="sr-only">Use setting</span> <!-- Enabled: "translate-x-5", Not Enabled: "translate-x-0" --> <span aria-hidden="true" class="translate-x-0 group-aria-checked:translate-x-5 pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out" ></span> </button> </div> <% end %>
import { Controller } from "@hotwired/stimulus" export default class extends Controller { connect() { } toggle() { this.element.ariaChecked = this.element.ariaChecked === "true" ? "false" : "true" } }
<button>
タグで実装しています。data-controller="switch"
でstimulus controllerを接続しますdata-action="click->switch#toggle keydown.space:stop:prevent->switch#toggle"
により、このトグルはマウスのクリックおよびスペースキーに応答するようになります。スペースキーでも使えるはアクセシビリティの要件ですdata-action
により、stimulus controllerのtoggle()
が呼び出されます。ここではaria-checked
属性を"true"/“false"の間で切り替えています<button>
タグのCSS classのaria-checked:bg-indigo-600
により、aria-checked="true"
の時だけボタンの背景が青く表示されるようになります<span aria-hidden="true" ...>
の要素はトグルの真ん中の丸いところで、これは左右に動く必要があります。これはCSSクラスにgroup-aria-checked:translate-x-5
と書けば実現できますHotwireの考え方は、なるべくブラウザのネイティブな機能を活かし、それを拡張していくというものです。HTMLだけでなくCSSを混ぜながら、バランスよくHTML/CSS/JavaScriptの機能を使っていきます。
ブラウザ機能を多角的に検討することは、Hotwireを綺麗に書くコツの一つと言えます。
昔からあるやり方ですが、ブラウザのネイティブな機能をさらに活かして、JavaScriptを全く使わないアプローチもあります。こうした方がさらにHotwireっぽいと言えるでしょう。
HTMLのチェックボックス要素を使うものです。
<% set_breadcrumbs [["Toggle Checkbox", component_path(:toggle)]] %> <%= render 'template', title: "Toggle Checkbox", description: "Toggle implemented with a Checkbox" do %> <!-- Enabled: "bg-indigo-600", Not Enabled: "bg-gray-200" --> <div class="text-center"> <label class="bg-gray-200 relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer select-none rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out outline-none has-[:focus]:ring-2 active:ring-2 ring-indigo-600 ring-offset-2 has-[:checked]:bg-indigo-600" role="switch" > <input type="checkbox" class="peer opacity-0 w-0 border-none"/> <span class="sr-only">Use setting</span> <!-- Enabled: "translate-x-5", Not Enabled: "translate-x-0" --> <span aria-hidden="true" class="translate-x-0 pointer-events-none inline-block h-5 w-5 rounded-full bg-white shadow ring-0 transition duration-200 ease-in-out peer-[:checked]:translate-x-5" ></span> </label> </div> <% end %>
<input type="checkbox"...>
)はネイティブでステートを持ちます。動きとしてはトグル的にオン・オフを切り替えます:checked
擬似セレクタを使ってCSSから読み取れますpeer
擬似セレクタと組み合わせると、チェックボックスステートに応じてトグル全体の表示をCSSだけで切り替えられますStimulusを使うコツとして、私は下記を意識するようにしています。
<input>
タグなど)のステートの活用を検討しますaria
属性をステートとすることを検討します