🫧

アクセサブルなスイッチUIの作り方 ——— React + Tailwind CSSで実装例をご紹介

に公開

モバイルアプリでよく見かける即時反映スイッチUI。これの実装例をご紹介します。

実装例

スイッチUIを実装するには、<button>要素にrole="switch"aria-checkedを付けましょう。
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Reference/Roles/switch_role

import { useState } from 'react';

function Switch() {
  const [isOn, setIsOn] = useState(false);

  return (
    <button
      role="switch"
      aria-checked={isOn}
      aria-label="ほげ"
      onClick={() => setIsOn((prev) => !prev)}
      className={`
        relative inline-flex h-6 w-10 items-center rounded-full
        transition-colors duration-200 ease-in-out
        focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2
        ${isOn ? 'bg-blue-600' : 'bg-gray-300'}
      `}
    >
      <span
        className={`
          inline-block h-4 w-4 rounded-full bg-white
          transition-transform duration-200 ease-in-out
          ${isOn ? 'translate-x-5' : 'translate-x-1'}
        `}
      />
    </button>
  );
}

ポイント

  • role="switch"を指定
  • aria-checkedで状態を明示(true/false
  • <button>要素なのでキーボード操作(Space/Enter)が自動的にサポートされる

よくない実装例

❌ div

function BadSwitchDiv() {
  const [isOn, setIsOn] = useState(false);

  return (
    <div
      onClick={() => setIsOn(!isOn)}
      className={`
        relative inline-flex h-6 w-10 items-center rounded-full cursor-pointer

        ${isOn ? 'bg-blue-600' : 'bg-gray-300'}
      `}
    >
      <span
        className={`
          inline-block h-4 w-4 rounded-full bg-white
          ${isOn ? 'translate-x-6' : 'translate-x-1'}
        `}
      />
    </div>
  );
}

ポイント

  • キーボード操作ができない(Tabでフォーカスできない)
  • スクリーンリーダーがボタンとして認識しない

❌ checkbox

function BadSwitchCheckbox() {
  const [isOn, setIsOn] = useState(false);

  return (
    <label className="relative inline-flex h-6 w-10 items-center rounded-full cursor-pointer">
      <input
        type="checkbox"
        checked={isOn}
        onChange={(e) => setIsOn(e.target.checked)}
        className="sr-only peer"
      />
      <span
        className={`
          absolute inset-0 rounded-full
          ${isOn ? 'bg-blue-600' : 'bg-gray-300'}
        `}
      />
      <span
        className={`
          absolute inline-block h-4 w-4 rounded-full bg-white
          ${isOn ? 'translate-x-5' : 'translate-x-1'}
        `}
      />
    </label>
  );
}

ポイント

  • チェックボックスとスイッチは意味が異なる
    • チェックボックス: 選択/非選択(フォーム送信時に使用)
    • スイッチ: 即座に効果が反映されるオン/オフの切り替え
  • スクリーンリーダーが「チェックボックス」と読み上げてしまう
  • フォーム送信が必要な設定画面などでは、<input type="checkbox">の実装も有効です

まとめ

スイッチUIを実装するには、<button>要素にrole="switch"aria-checkedを付けましょう。

Discussion