SvelteKitでポップアップを作るときのエラー解決法|アクセシビリティ対応も解説
大平 恵美
大平 恵美
2025-02-14
SvelteKitでポップアップを開発する際に発生する「クリックできるが、キーボード操作ができない」エラーの原因と解決策を解説します。適切なHTML要素の選び方や、キーボード対応の方法、アクセシビリティの基本を初心者向けにわかりやすくまとめました。SvelteKitを使う際に避けられないエラーを解決し、より多くのユーザーに優しい設計を目指しましょう。
あなた:

SvelteKitでポップアップを開発しています。エラーが出たので解析してください。

Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler. Consider whether an interactive element such as <button type="button"> or <a> might be more appropriate
https://svelte.dev/e/a11y_click_events_have_key_eventssvelte(a11y_click_events_have_key_events)
<div> with a click handler must have an ARIA role
ChatGPT:

Svelteのアクセシビリティ(a11y)警告についてですね。
エラーメッセージの内容から、以下の2つの問題が発生している可能性があります。

1. click イベントを持つ非インタラクティブ要素にキーボードイベントがない

警告:

Visible, non-interactive elements with a click event must be accompanied by a keyboard event handler.
(クリックイベントを持つ可視の非インタラクティブ要素には、キーボードイベントを追加する必要があります。)

原因:
<div><span> のような非インタラクティブな要素に on:click を設定すると、
キーボード操作(EnterSpace キー)では操作できません。

解決策:

  • 適切な要素を使う → 例えば <button><a> を使用する
  • キーボードイベントを追加するon:keydownEnterSpace を対応させる

修正例:

<!-- ❌ NG: 非インタラクティブな要素に click イベントだけを設定 -->
<div on:click={handleClick}>Click me</div>

<!-- ✅ OK: button を使う -->
<button on:click={handleClick}>Click me</button>

<!-- ✅ OK: キーボードイベントを追加する -->
<div tabindex="0" role="button" on:click={handleClick} on:keydown={(e) => (e.key === "Enter" || e.key === " ") && handleClick()}>
  Click me
</div>

2. <div>click を使う場合は ARIA role が必要

警告:

<div> with a click handler must have an ARIA role.
(クリックハンドラー(クリックされたときの動き)を持つ <div> は ARIA role を持つ必要があります。)

原因:
<div on:click={handleClick}> にはデフォルトのアクセシビリティ情報がないため、
スクリーンリーダーなどでボタンのように認識されません。

解決策:

  • <div>role="button" を設定
  • tabindex="0" を追加してフォーカス可能にする

修正例:

<!-- ❌ NG: role なしの <div> に click ハンドラーだけ設定 -->
<div on:click={handleClick}>Click me</div>

<!-- ✅ OK: role="button" を追加 -->
<div role="button" tabindex="0" on:click={handleClick} on:keydown={(e) => (e.key === "Enter" || e.key === " ") && handleClick()}>
  Click me
</div>

ベストプラクティス

  • 可能なら <button> を使う(デフォルトでアクセシビリティが考慮されている)
  • どうしても <div> を使うなら role="button"tabindex="0" を追加
  • キーボードイベント(on:keydown)も設定し、EnterSpace をサポート

まとめ

❌ NG ✅ OK
<div on:click={handleClick}>Click me</div> <button on:click={handleClick}>Click me</button>
<div on:click={handleClick}>Click me</div> `<div role="button" tabindex="0" on:click={handleClick} on:keydown={(e) => (e.key === "Enter"

Svelte で開発する際は、アクセシビリティを意識して要素を適切に選ぶのが大事ですね!

あなた:

div要素やspanにクリックの指示をしていることが原因なのですね。本来の使い方と間違えているということですか。

ChatGPT:

その通りです!Svelte(というかHTML全体)のルールとして、<div><span>本来インタラクティブな要素ではない ため、click を直接設定すると間違った使い方になってしまいます。

なぜ間違いなのか?

  • <div><span> は「グループ化」や「装飾」のための要素であり、ユーザーが操作することを前提としていない
  • キーボード操作(Tabキー でのフォーカスや Enter / Space でのクリック)に対応していない
  • スクリーンリーダーが「クリックできる」と認識できない

そのため、もしクリック可能にしたい場合は 適切な要素 を使うか、アクセシビリティの設定を追加 する必要があります。


正しい使い方

❌ 間違い ✅ 正しい
<div on:click={handleClick}>Click me</div> <button on:click={handleClick}>Click me</button>
<span on:click={handleClick}>Click me</span> <a href="#" on:click={handleClick}>Click me</a>

どうしても <div> を使いたい場合

もしスタイルの都合などで <div> を使いたい場合は、次のように アクセシビリティ対応 を追加します。

<div role="button" tabindex="0" on:click={handleClick} 
     on:keydown={(e) => (e.key === "Enter" || e.key === " ") && handleClick()}>
  Click me
</div>
  • role="button" → スクリーンリーダーに「ボタンである」と認識させる
  • tabindex="0" → キーボードで Tab を押したときにフォーカスできるようにする
  • on:keydownEnterSpace キーでクリックできるようにする

まとめ

<div><span> には基本的に click を設定しない!
ボタンなら <button>、リンクなら <a> を使うのがベスト!
どうしても <div> を使うならアクセシビリティ対応を追加する!

Svelteでは、こうしたHTMLの基本ルールを守ることで、より良いコードが書けます! 🚀

Gemini:

<div>要素や<span>要素は、本来インタラクティブな要素として意図されていません。これらの要素にclickイベントハンドラを設定すること自体は可能ですが、いくつかの問題を引き起こす可能性があります。

本来の使い方との違い:

  • 意味論的な誤り: <div><span>は、コンテンツのグループ化や装飾のために使用される汎用的な要素です。一方、ボタンやリンクは、特定のインタラクション (クリック、移動など) を示す意味を持つ要素です。<div><span>clickイベントを設定することは、これらの要素が本来持つ意味合いと矛盾します。
  • アクセシビリティの問題: スクリーンリーダーなどの支援技術は、要素の持つ意味 (semantic) に基づいて情報をユーザーに伝えます。<div><span>clickイベントを設定しても、スクリーンリーダーはそれがクリック可能な要素であることを認識できません。そのため、視覚障碍者などのユーザーは、その要素を操作できない可能性があります。
  • ユーザーエクスペリエンスの低下: キーボード操作のみでウェブサイトを利用するユーザーにとって、<div><span>に設定されたclickイベントは操作できません。

SvelteKitが警告する理由:

SvelteKitは、開発者がウェブアクセシビリティを意識したコードを書くことを支援するために、このような警告を表示します。これは、より多くのユーザーがウェブサイトを利用できるようにするための重要な取り組みです。

推奨される解決策:

  • 適切な要素の使用: クリック操作が必要な場合は、<button>要素や<a>要素 (リンクの場合) など、意味的に正しいインタラクティブ要素を使用することを推奨します。
  • ARIAロールの指定: どうしても<div><span>を使用する必要がある場合は、role属性で適切なARIAロール (例えば、role="button"role="link") を指定し、スクリーンリーダーに要素の意味を伝える必要があります。

まとめ:

<div>要素や<span>要素にclickイベントハンドラを設定することは、本来の使い方ではありません。ウェブアクセシビリティの観点からも、適切な要素を使用するか、ARIAロールを正しく指定することが重要です。

あなた:

アクセシビリティをカタカナを使わずに簡単に説明してください。

ChatGPT:

アクセシビリティをカタカナを使わずに簡単に説明すると、

「どんな人でも、どんな道具を使っていても、無理なく使えるようにすること」 です!😊


なぜ大事なの?

人によって、コンピュータの使い方は違います。
たとえば…
マウスを使わずにキーボードだけで操作する人
目が見えにくく、画面を読み上げる機能(音声)を使う人
スマホの画面が小さく、ボタンを押しにくい人

こういう人たちも 「困らずに使える」ようにする工夫 が大切です。


どんな工夫が必要?

1️⃣ キーボードでも操作できるようにする
 → クリックだけじゃなく、「Enterキー」や「スペースキー」でも動くようにする

<div role="button" tabindex="0" on:click={doSomething} on:keydown={(e) => (e.key === "Enter" || e.key === " ") && doSomething()}>
  ここを押す
</div>

🔹 こうすると、キーボードでも操作できる!

2️⃣ 画面を読み上げる人のために、説明をつける
 → alt をつけて、画像の意味を伝える

<img src="photo.jpg" alt="夕日の写真">

🔹 目が見えない人でも、画面読み上げソフトが「夕日の写真」と教えてくれる!

3️⃣ 小さいボタンを押しやすくする
 → 余白をつけて、スマホでも押しやすくする

<button class="p-4">押す</button>

🔹 スマホで小さすぎるボタンは、押しにくいからね!


簡単にまとめると…

📌 どんな人でも、どんな道具を使っていても、無理なく使えるようにすること!
📌 「マウスがなくてもOK」「画面を見なくてもOK」「スマホでも押しやすい」ようにする工夫!

小さな工夫で、たくさんの人が快適に使えるようになります!😊

あなた:

インタラクティブとは簡単に何ですか。

ChatGPT:

「インタラクティブ(Interactive)」 とは、簡単に言うと 「ユーザーが操作できるもの」 という意味です。

具体的には?

インタラクティブな要素とは、クリック・タップ・キーボード操作などで ユーザーが関与できる要素 のことを指します。例えば:

インタラクティブな要素(操作できる要素)

  • <button> (ボタン → クリック可能)
  • <a> (リンク → クリックで移動)
  • <input> (入力欄 → 文字を入力できる)
  • <select> (ドロップダウン → 選択できる)
  • <textarea> (テキストエリア → 長文を入力できる)

非インタラクティブな要素(操作できない要素)

  • <div>(ブロックのグループ化)
  • <span>(テキストの装飾)
  • <p>(段落)
  • <h1>(見出し)
  • <img>(画像)

なぜインタラクティブ要素を使うべき?

Svelte(というかHTML全体)では、ユーザーが操作する要素には 適切なインタラクティブ要素を使う ことが推奨されています。

例えば、以下のコードは 間違った使い方 です:

<div on:click={handleClick}>Click me</div>

なぜなら、<div> は本来インタラクティブな要素ではなく、キーボード操作も考慮されていないからです。

正しい書き方

<button on:click={handleClick}>Click me</button>

こうすると、キーボードやスクリーンリーダーも適切に動作します!


インタラクティブ要素を使うポイント

  1. クリック可能なら <button> を使う
  2. リンクなら <a> を使う
  3. どうしても <div><span> を使いたい場合は、roletabindex を追加する

これを意識すると、アクセシビリティ(a11y)にも対応できるので、使いやすいWebアプリが作れます!💡

あなた:

functionを使ってscriptタグ内に Enterキーまたはスペースキーが押されたら closeModal を実行する関数を記載することにしました。 以下のコードはletで定義していないのに実行できました。event.keyはどこから出てきたのですか。

<script>
    function handleKeydown(event) {
        // Enterキーまたはスペースキーが押されたら closeModal を実行
        if (event.key === "Enter" || event.key === " ") {
            closeModal();
        }
    }
</script>

<div 
    class="fixed inset-0 bg-black/50 flex items-center justify-center" 
    on:click={closeModal} 
    role="button" 
    tabindex="0" 
    on:keydown={handleKeydown} 
>

event.key

ChatGPT:

良い質問ですね! event.key はどこから来るのか、分かりやすく説明します。


1. event はどこから来るのか?

eventブラウザが自動で提供するオブジェクト です。
これは、キーボードやマウスなどの イベント(on:keydown など)が発生したときに、自動的に関数の引数として渡される ものです。

つまり、以下のように handleKeydown(event)event は、Svelte(というかJavaScript)が自動的に渡してくれます。

<script>
    function handleKeydown(event) {
        console.log(event);  // ← ここで event の中身を確認できる
        if (event.key === "Enter" || event.key === " ") {
            closeModal();
        }
    }
</script>

<div 
    tabindex="0" 
    on:keydown={handleKeydown}
>
    モーダル
</div>

このコードで Enterキーを押すと、console.log(event) によって event の中身が確認できます!
(ブラウザの開発者ツールのコンソールで表示されます)


2. event.key は何?

  • event「キーボードイベント」の情報が入ったオブジェクト です。
  • event.key押されたキーの名前を取得 できます。

例えば、次のコードを試すと、キーを押したときに event.key の値が分かります。

キー入力を調べる例

<script>
    function handleKeydown(event) {
        console.log("押したキー:", event.key);
    }
</script>

<input type="text" on:keydown={handleKeydown} placeholder="何かキーを押してみて!" />

このコードで A を押すと、コンソールに 押したキー: a と表示されます。


3. なぜ let event を宣言しないのか?

通常の変数(let name = "Svelte" のようなもの)は 自分で作る必要があります が、eventJavaScript が自動で渡してくれる ので let event のように宣言する必要はありません。

関数の引数として event を受け取るだけでOK!

function handleKeydown(event) {
    console.log(event.key);  // どのキーが押されたかを表示
}

これは、JavaScript のイベントハンドラの基本的な仕組みです。


まとめ

event は、イベントが発生すると JavaScript が自動で渡してくれるオブジェクト
event.key で、どのキーが押されたかを取得できる
let event のように宣言しなくてもOK(ブラウザが自動で渡す)

JavaScript のイベントを理解する良いきっかけですね! 😃

🎯結論

  1. SvelteKitのエラーの原因は、非インタラクティブな要素(<div><span>)に click を設定したこと

    • <div><span> は本来クリック可能な要素ではないため、アクセシビリティ上の問題が発生。
    • 解決策として、適切なインタラクティブ要素(<button><a>)を使用するか、role="button"tabindex="0" を追加し、キーボードイベント(on:keydown)を設定する。
  2. 「インタラクティブ」とは、ユーザーが操作できる要素のこと

    • <button><a> はインタラクティブ要素として設計されており、クリックやキーボード操作が可能。
    • <div><span> はインタラクティブではなく、イベントを追加する場合は適切な設定が必要。
  3. キーボード操作(Enterキー・スペースキー)でポップアップを閉じる処理を関数にまとめる

    • handleKeydown(event) 関数を作成し、event.key をチェックして closeModal() を実行。
    • event はブラウザが自動で提供するオブジェクトであり、明示的に let event と宣言する必要はない。
  4. SvelteKitのアクセシビリティエラーを防ぐためのベストプラクティス

    • クリック可能な要素には <button> を使用する。
    • どうしても <div> を使う場合は、role="button"tabindex="0" を追加する。
    • キーボード操作 (on:keydown) にも対応し、スクリーンリーダーの互換性を確保する。

この修正により、エラーが解消され、アクセシビリティにも対応したポップアップが実装できます! 🚀