fix(a11y): aria/role 欠落を補完(JanCode/CidrCalculator/RegexMatchTester) - #665
Conversation
issue #663 で検出した DADS 準拠監査の aria/role 欠落を補完する。 - JanCode: バーコード svg に role="img" を付与(QrCode と揃え、aria-label を accessible name として SR が確実に読めるようにする) - CidrCalculator: 重複検出モードの行エラー一覧に role="alert" を付与(親 aria-live の初期コンテンツ問題を回避し解析エラーを SR に確実に通知) - RegexMatchTester: クリック可能な mark に role="button" / tabIndex / aria-pressed / aria-label / onKeyDown を付与しキーボード・SR 操作可能にする 各修正に陽性対照 E2E を追加(属性・キーボード操作が外れると fail する設計)。
🖼️ Visual Regression Test 結果
|
fumtas1k
left a comment
There was a problem hiding this comment.
レビュー結果: LGTM(self-PR のため Approve 不可、コメントで記録)✅
issue #663 の 3 項目(JanCode role="img" / CidrCalculator role="alert" / RegexMatchTester の <mark> 操作可能化)を過不足なく実装しており、CI も全 green(test / e2e / VRT 60 件 pass)。多角的観点で評価しました。
セキュリティ
- 問題なし。
aria-labelに差し込むresult.fullCode/m.value(ユーザー入力)はいずれも React の属性値として render されるためエスケープされ、反射型 XSS の経路にならない。dangerouslySetInnerHTMLも不使用。
アーキテクチャ / 一貫性
- JanCode の
role="img"付与はQrCode.tsxの既存実装(生成 SVG へのrole="img"注入)と方針が揃っており、SVG の accessible name 露出パターンが統一された点が good。 - CidrCalculator は live region 化対象を行エラー一覧のみに限定し、pairs テーブル・「重複なし」メッセージには付けない切り分けが適切。
ロジック / フロントエンド
<mark role="button">+tabIndex+onKeyDown(Enter/Space) +aria-pressedの構成は妥当。Space にpreventDefault()を入れてページスクロールを抑止している点も正しい。空マッチに(空マッチ)を付けたaria-label分岐も適切。
テスト
- 3 件とも陽性対照(属性を外すと
getByRole取得不能で fail)になっており test-gates の趣旨に合致。特に regex spec がaria-pressed: false → trueの遷移でonKeyDown経路まで観測している点が良い。
任意(非ブロッキング)の指摘
1. role="alert" のキーストロークごとの再読み上げ(CidrCalculator)
overlapResult は useMemo([mode, overlapInput]) で debounce なしに毎キーストローク再計算される(CidrCalculator.tsx:287)。role="alert" は暗黙 aria-live="assertive" + aria-atomic="true" のため、エラーが残っている間は入力 1 文字ごとにエラー一覧全体が assertive に再読み上げされ、SR ユーザーには割り込みが連続して冗長になり得ます。
- エラー通知を確実にする意図は理解できますが、複数行 textarea で打鍵頻度が高い UI では
role="status"(polite)への変更、もしくは overlap 計算の debounce 化で chattiness を抑える選択肢もあります。判断はお任せしますが、別 issue 化でも良いと思います。
2. <mark> の tab stop 数(RegexMatchTester、軽微)
g フラグ + 長文では全マッチがそれぞれ tab stop になり、キーボードユーザーが多数の focus 位置を踏むことになります。下部の ResultTable でも選択できるため実害は小さいですが、将来的に roving tabindex(コンテナ 1 stop + 矢印キー移動)にすると navigation が軽くなります。これも別 issue 候補。
3. 排他選択の ARIA セマンティクス(RegexMatchTester、設計上の選択肢)
「1 つだけ選択」を複数の aria-pressed トグルボタンで表現しています。WAI-ARIA 的には許容範囲ですが、厳密には radiogroup/radio の方が排他選択の意味に近いです。現状のままで問題はないので参考まで。
いずれも本 PR をブロックする欠陥ではありません。スコープも明確で、このまま merge して良いと判断します。
Generated by Claude Code
issue #663 PR レビュー指摘 #1 への対応。overlapResult は毎キーストローク再計算 されており、行エラー一覧の role="alert"(暗黙 assertive + atomic)がエラー継続中は 入力 1 文字ごとに全体を SR へ割り込み再読み上げしてしまう問題があった。 overlapInput を useDebouncedValue(300ms) で debounce してから計算することで、 打鍵が止まってから 1 度だけエラー一覧を更新する。エラー出現時の確実な通知 (role="alert")は維持しつつ、SR ユーザーへの chattiness を抑制する。 入力欄自体は即時の overlapInput を value に保つため打鍵応答は変わらない。
|
レビューありがとうございます。任意指摘 3 点を以下のとおり対応しました。 #1 role="alert" のキーストロークごと再読み上げ → 本 PR で対応(0b411af)
#2 / #3 → follow-up issue 化
いずれも P3 として起票しました。#2 と #3 は併せて UX を見直す価値があるため相互参照を記載しています。 Generated by Claude Code |
再レビュー: 指摘 3 点すべて解決を確認 ✅迅速なご対応ありがとうございます。 #1
#2 / #3 → follow-up issue 化を確認
結論当初の LGTM 判断は維持です。本 PR スコープで対応すべき指摘(#1)は解消され、残りは適切に issue 化されました。CI(test / VRT)green、e2e の green 確認後にこのまま merge して問題ありません。 Generated by Claude Code |
概要
issue #663 で検出した DADS 準拠監査の aria / role 欠落・不整合を補完する。3 件とも独立した a11y 修正。
Closes #663
変更内容
1. JanCode: バーコード svg に
role="img"を付与src/components/tools/JanCode.tsxaria-labelはあったがrole="img"がなく、<svg>のデフォルト role はブラウザ依存。role="img"を付与して SR がaria-labelを確実に accessible name として読めるようにする(ARIA 1.2)。QrCode.tsxが生成 SVG にrole="img"を注入済みなのと実装を揃えた。2. CidrCalculator: 重複検出の行エラー一覧に
role="alert"を付与src/components/tools/CidrCalculator.tsx<section aria-live="polite">は既存だが、section 全体が一度にマウントされると live region の初期コンテンツは SR に確実に通知されない。解析エラーは重要なため、エラーコンテナ<div>にrole="alert"(暗黙 assertive + atomic)を付与して確実に通知する。pairs テーブルや「重複なし」メッセージには付けない。3. RegexMatchTester: クリック可能な
<mark>をキーボード・SR 操作可能にsrc/components/tools/RegexMatchTester.tsxonClickを持つ<mark>がtitleのみでマウス専用だった。role="button"/tabIndex={0}/aria-pressed(選択状態)/aria-label(空マッチは「(空マッチ)」付き)/onKeyDown(Enter・スペースで選択)を付与。global.cssの:where(..., [role='button'], ...):focus-visibleglobal rule が自動適用するため追加 CSS 不要。outline-noneは未使用。テスト(陽性対照 E2E)
属性・キーボード操作が外れると fail する設計で各 spec に追加:
tests/e2e/jan-code.spec.ts:getByRole('img', { name: /バーコード/ })でrole="img"+ accessible name を検証tests/e2e/regex-visualizer.spec.ts:getByRole('button', { name: /マッチ 1/ })でrole="button"を検証し、Enter キーでaria-pressedがfalse → trueに変わる(onKeyDown経路)ことを検証tests/e2e/cidr-calculator.spec.ts: 不正 CIDR(10.0.0.0/99)入力後にgetByRole('alert')でエラー一覧コンテナが取得できることを検証検証結果
node_modules/.bin/astro checknpm run test(unit)npm run test:e2e(対象 3 spec + a11y-live-region)関連
https://claude.ai/code/session_01QpTRCLJWorrqTYT5WfdVxQ
Generated by Claude Code