🐰

contenteditable属性を指定した要素の外でクリックしてもフォーカスされる問題を解消する

2024/07/02に公開

デザインエンジニアのりょーたです。
FigmaでFigTodoというタスク管理用のプラグインを開発しています。

https://www.figma.com/community/plugin/1376174862254820112/figtodo

今回は、以前から発生していた、contenteditable属性を指定した要素でないところをクリックしても、contenteditable属性を指定した要素でfocusイベントが発生する不具合を解消したため、その方法をご紹介します。


入力範囲外をクリックしても編集モードになる

結論

contenteditable属性を、focusイベントが発生した場合にのみ有効にするように変更します。

 const [isEditing, setIsEditing] = useState(false);

 <div
-   contentEditable
+   contentEditable={isEditing}
    onBlur={() => setIsEditing(false)}
    onFocus={() => setIsEditing(true)}
    tabIndex={0}
 >
    {text}
 </div>

色々試してみたところ、contentEditable属性が有効な場合に親要素のfocusイベントが一番近い要素に継承されているのかな、と思います。(正確な答えではないため、リソースを見つけられた方はコメントいただけますと幸いです)


contenteditable属性を指定していない要素をクリックしてもフォーカスが継承されない

おまけ

contenteditable属性は便利ですが、アクセシビリティの観点からは、適切なWAI-ARIA属性を追加した方が良いです!
以下は、先ほどのコードを改善した例です。

 <div
    contentEditable={isEditing}
    onBlur={() => setIsEditing(false)}
    onFocus={() => setIsEditing(true)}
    tabIndex={0}
+   role={isEditing ? 'textbox' : undefined}
+   aria-multiline={isEditing ? true : undefined}
 >
    {text}
 </div>

textboxロールは、自由形式テキストの入力ができる要素を識別するために使用されます。
このケースでは、isEditingtrueのときにtextboxを設定し、falseのときにundefinedを設定して属性を削除します。

aria-multiline="true"が設定されている場合、支援技術はテキストボックスが複数行入力に対応していることをユーザーに知らせます。
このケースでは、isEditingtrueのときにtrueを設定しfalseのときにundefinedを設定して属性を削除します。

これにより、contenteditable属性が動的に切り替わる際に、適切なWAI-ARIA属性も一緒に設定され、アクセシビリティが向上します。

参照

https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Roles/textbox_role

以上です😊

Discussion