TL;DR
一部の UI/CSSライブラリ(DOM要素をラップ/上書きするタイプ) を使うと、div
直書きでは検知できる a11y ルール(例:クリックに対するキーボード対応の要求)が、ラップ済みのカスタムコンポーネントでは検知されない ことがある。
手元では Biome で再現。原理的に他ツールでも起きがち。
背景 / 結論
ちょっと検証した結論:
「DOMラップ/override型のUI/CSSライブラリを使うと、キーボード操作等の欠落がリンタで拾いづらい/拾えないケースがある」
理由は、a11yルールが “素のタグ名(<div>
など)” を見て判定 しているものが多いため。
DOM 属性を透過させるだけの ラッパーを挟むと、静的解析時点では “ただのカスタムコンポーネント” に見える ため、useKeyWithClickEvents
的な検知が働かないことがある。
最小再現コード
import type { DOMAttributes } from "react";
interface ClickableDivProps extends DOMAttributes<HTMLDivElement> {}
export const ClickableDiv = ({ children, ...props }: ClickableDivProps) => {
return <div {...props}>{children || "ClickableDiv"}</div>;
};
interface ClickableInputProps extends DOMAttributes<HTMLInputElement> {}
export const ClickableInput = ({ children, ...props }: ClickableInputProps) => {
return <input {...props} />;
};
const Counter = () => {
return (
<>
<p>landing zone</p>
<div onClick={() => { alert("プレーンなdiv clicked"); }}>
プレーンなdiv
</div>
{/* ↑ ここは lint の a11y/useKeyWithClickEvents が検知される */}
{/* ↓ 以下2つはキーボードで操作できない問題があるが、解析ツールでは検知できないことがある */}
<ClickableDiv onClick={() => { alert("div clicked"); }} />
<ClickableInput onClick={() => { alert("input clicked"); }} />
</>
);
};
export default Counter;
- プレーンな
<div onClick>
では、「Enter/Spaceなどのキーボード対応も用意してね」 という警告が出る - しかし
<ClickableDiv onClick>
のようなラップ要素では出ない(最終的に何のタグになるか、静的解析が追えないため)
補足:再現は Biome で確認。ルール実装が 「JSXのタグ名ベース」 のツールでは同様に起こり得る。
なぜ起きる?
- a11yルールの多くは 「どのタグにどのイベントを付けたか」 を見て判定
- ラッパーが
{...props}
を 素通し しているだけだと、中で最終的に何のタグになるのか 分からない - UI/CSSライブラリによっては DOMが余計にネスト したり prop注入 が行われ、“素のタグ” が表面に出ない
実害(見落としポイント)
- マウスでは動くがキーボードで操作できない(Enter/Spaceで発火しない、フォーカス不能)。
- スクリーンリーダー上の ロール(
role="button"
)やフォーカス移動 が崩れる。 - 「リンタに怒られない=安全」ではない 状態が生まれる。
まとめ
UI/CSSライブラリ、ものによってはa11yチェックをうまく検知できないケースがある。
選定時にも気をつけよう。
もちろん、自動チェックだけでなくユーザーテストなど実プロダクトでの検証をしっかりやろう