HTML仕様の落とし穴:`??=` から `||=` への修正で要素IDの自動生成が正しく機能するように
lexxy-editor カスタム要素の ID 自動生成が、HTML の element.id の仕様に起因するバグにより機能していなかった問題を修正しました。??=(nullish 代入)を ||=(論理 OR 代入)に変えるだけで、意図通りの動作が実現されています。
背景
HTML 仕様では、element.id は未設定の場合に null や undefined ではなく、空文字列 "" を返します。JavaScript の nullish 代入演算子 ??= は左辺が null または undefined のときだけ右辺を評価するため、"" に対しては代入が行われません。結果として、id 属性が設定されていない lexxy-editor 要素は自動生成 ID を受け取れず、空のまま残る状態が続いていました。
この問題は、コンポーネントの connectedCallback における一行の演算子選択に起因するものです。Web Components の開発では element.id が "" を返すという挙動は見落とされやすく、今回のケースはその典型例といえます。
技術的な変更
修正は src/elements/editor.js の connectedCallback 内の1行のみです。
変更前:
this.id ??= generateDomId("lexxy-editor")
変更後:
this.id ||= generateDomId("lexxy-editor")
||=(論理 OR 代入) は左辺が falsy(null・undefined・""・0・false など)のときに右辺を代入するため、element.id が空文字列であるケースも正しく処理できます。"my-custom-id" のように明示的な ID が設定されている場合は truthy なので代入はスキップされ、既存の ID は保持されます。
合わせて test/browser/tests/editor/id_generation.test.js が新規追加され、以下の4つのシナリオが Playwright でカバーされています:
- ID 未設定時に
lexxy-editor-プレフィックスの ID が自動生成されること - コンテンツ要素の ID がエディタ ID から
${editorId}-contentの形式で派生すること - 複数の
lexxy-editorが互いに異なる一意の ID を持つこと - 明示的に設定された ID が上書きされずに保持されること
設計判断
??= ではなく ||= を選択する判断は、HTML の element.id が空文字列を返すという仕様への対応として最小限かつ正確なアプローチです。
??= から ||= への変更は、意味的には「値が存在しない場合」から「値が有効でない場合」への条件の拡張です。ID の文脈では空文字列は無効な値であるため、この拡張は適切です。なお、この変更により id = "" のように明示的に空文字列が設定された場合もIDが自動生成されるようになります。これは、空の ID を意図的に利用する特殊なケースを除き、ほとんどの状況で望ましい挙動といえます。
テストを修正と同時に追加することで、同様の退行を防ぐ安全網が整備されています。
まとめ
??= と ||= の1文字の違いが、HTML の element.id 仕様との相互作用により要素 ID の自動生成を完全に無効化していた問題を解消しました。演算子の選択が DOM API の返値仕様と噛み合わないと、コードは構文的に正しくても意図した動作をしないというケースを端的に示す変更です。