mcpField
F
framework-accessibility

framework-accessibility

github.com/community-access開発429250 回インストール今日更新
リポジトリ

framework-accessibility について

React、Next.js、Vue、Angular、Svelte、Tailwind CSS のアクセシビリティパターンをまとめたスキルです。フロントエンド開発者向けに、キーボード操作やフォーカス、動的コンテンツ、コントラストの問題と修正例を示します。

主な機能

  1. 01フレームワーク別のよくある問題
  2. 02コード修正テンプレート
  3. 03キーボード操作とフォーカス管理
  4. 04Tailwind CSS の安全なコントラスト例

活用シーン

  1. 01フロントエンドコンポーネントの監査
  2. 02フレームワーク固有のフォーカス問題の修正
  3. 03Tailwind インターフェースの色コントラスト確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/community-access/accessibility-agents --skill framework-accessibility

インストール後、Claude Code で/framework-accessibilityを入力して読み込まれたか確認します。

詳細

フレームワーク固有のアクセシビリティパターン

React / Next.js

よくある落とし穴
パターン問題修正方法
<div> の onClickキーボードで操作できません<button> を使うか、role="button"、tabIndex={0}、onKeyDown を追加します
dangerouslySetInnerHTMLアクセシビリティに配慮されていないコンテンツが挿入される可能性があります挿入する HTML の ARIA、見出し、代替テキストを監査します
ルートとしての React.Fragmentランドマークツリーが壊れる可能性がありますフラグメントがランドマークのネストを妨げないようにします
リストの key がない再レンダリング時にフォーカスが失われる可能性がありますインタラクティブなリストでは安定したキー(配列のインデックス以外)を使います
フォーカストラップのないポータルフォーカスが背景に移動する可能性がありますポータルのコンテンツを FocusTrap コンポーネントで囲みます
フォーカス管理に useEffect を使用マウント時にフォーカスが設定されない可能性があります適切な依存配列を指定して、useRef と useEffect を使います
修正テンプレート
// Bad: div as button
<div onClick={handleClick}>Submit</div>

// Good: semantic button
<button onClick={handleClick}>Submit</button>

// Bad: image without alt in Next.js
<Image src="/hero.jpg" width={800} height={400} />

// Good: image with alt
<Image src="/hero.jpg" width={800} height={400} alt="Team collaborating in a modern office" />

// Bad: no focus management on route change
useEffect(() => {
  // nothing
}, [location]);

// Good: focus management on route change
useEffect(() => {
  const mainContent = document.getElementById('main-content');
  if (mainContent) {
    mainContent.focus();
    mainContent.scrollIntoView();
  }
}, [location]);

// Bad: link opening new tab
<a href={url} target="_blank">Resource</a>

// Good: link with new tab warning
<a href={url} target="_blank" rel="noopener noreferrer">
  Resource <span className="sr-only">(opens in new tab)</span>
</a>

Vue

よくある落とし穴
パターン問題修正方法
ユーザーコンテンツを含む v-htmlアクセシビリティに配慮されていないマークアップが挿入される可能性があります挿入する HTML をサニタイズして監査します
ライブリージョンでの v-if要素が DOM から削除され、通知が機能しなくなりますライブリージョンでは代わりに v-show を使います
フォーカス管理のない <transition>コンテンツの切り替え時にフォーカスが失われます@after-enter フックでフォーカスを管理します
<body> への <teleport>コンテンツがアプリのランドマークツリーの外側に配置されますテレポートしたコンテンツにランドマークのロールを追加します
修正テンプレート

<div v-if="message" aria-live="polite">{{ message }}</div>


<div v-show="message" aria-live="polite">{{ message }}</div>


<transition name="fade">
  <div v-if="showModal" class="modal">...</div>
</transition>


<transition name="fade" @after-enter="focusModal">
  <div v-if="showModal" ref="modal" class="modal" tabindex="-1">...</div>
</transition>

Angular

よくある落とし穴
パターン問題修正方法
[aria-label] バインディング無効です。ARIA はプロパティではありません[attr.aria-label] を使います
trackBy のない *ngForリストの再レンダリング時にフォーカスが失われますtrackBy 関数を追加します
LiveAnnouncer がないルートの変更が通知されませんLiveAnnouncer をインジェクトして、ナビゲーションを通知します
OnPush とライブリージョンの併用変更検知が実行されない可能性がありますChangeDetectorRef.markForCheck() を使います
修正テンプレート
// Bad: ARIA binding
<button [aria-label]="label">X</button>

// Good: ARIA attribute binding
<button [attr.aria-label]="label">X</button>

// Bad: ngFor without trackBy
<li *ngFor="let item of items">{{ item.name }}</li>

// Good: ngFor with trackBy
<li *ngFor="let item of items; trackBy: trackById">{{ item.name }}</li>

// Route change announcements
constructor(private liveAnnouncer: LiveAnnouncer, private router: Router) {
  this.router.events.pipe(
    filter(event => event instanceof NavigationEnd)
  ).subscribe((event: NavigationEnd) => {
    this.liveAnnouncer.announce(`Navigated to ${this.getPageTitle()}`);
  });
}

Svelte

よくある落とし穴
パターン問題修正方法
フォーカス管理のない {#if}コンテンツが表示されたときにフォーカスが失われますuse:action を使って新しいコンテンツにフォーカスします
モーション設定の確認がない transition:ユーザーの設定に関係なくアニメーションが再生されますprefers-reduced-motion の確認を追加します
インタラクティブでない要素の on:clickキーボードで操作できません<button> を使うか、キーボードイベントハンドラーを追加します
修正テンプレート

<div on:click={toggle}>Toggle</div>


<button on:click={toggle}>Toggle</button>


<div transition:fly={{ y: 200 }}>Content</div>


<div transition:fly={{ y: reducedMotion ? 0 : 200, duration: reducedMotion ? 0 : 300 }}>Content</div>

<script>
  const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
</script>

Tailwind CSS

よくある落とし穴
パターン問題修正方法
outline-noneフォーカスインジケーターが削除されますring-2 ring-offset-2 focus-visible:ring-blue-500 と組み合わせます
bg-white 上の text-gray-400コントラスト比が 4.5:1 を下回りますtext-gray-600 またはそれより濃い色を使います
motion-reduce: バリアントがないアニメーションがユーザーの設定を無視しますmotion-reduce:transition-none を追加します
focus: スタイルがない視認できるフォーカスインジケーターがありませんfocus:ring-2 focus:ring-blue-500 を追加します
sr-only がないスクリーンリーダー向けのテキストが利用できません<span class="sr-only">description</span> を追加します
コントラストに安全な Tailwind の組み合わせ
背景テキストの最小色比率
bg-whitetext-gray-6004.55:1
bg-whitetext-gray-7006.62:1
bg-gray-50text-gray-7006.29:1
bg-gray-900text-gray-3005.92:1
bg-blue-600text-white5.23:1
bg-red-600text-white4.54:1
bg-green-700text-white4.58:1
修正テンプレート

<button class="bg-blue-500 text-white px-4 py-2 rounded outline-none">
  Submit
</button>


<button class="bg-blue-500 text-white px-4 py-2 rounded focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2">
  Submit
</button>


<p class="text-gray-400">Important information</p>


<p class="text-gray-700">Important information</p>


<div class="transition-transform duration-300 hover:scale-105">Card</div>


<div class="transition-transform duration-300 hover:scale-105 motion-reduce:transition-none motion-reduce:hover:scale-100">Card</div>

コメント