`<wa-combobox>` に「オプション動的作成」機能と `input` イベントを追加

shoelace-style/webawesome

<wa-combobox>allow-create 属性による新規オプションの動的生成機能と、入力時の input イベント発火が追加されました。あわせて allow-custom-value 使用時の2つのバグが修正され、コンボボックスの実用性が大幅に向上しています。

背景

従来の <wa-combobox> は、ドロップダウンに存在する選択肢を選ぶ操作に限られており、ユーザーが入力したテキストをそのまま新しいオプションとして追加する手段がありませんでした。タグ入力やフリーテキスト選択のようなUIパターンを実現するには、コンポーネント外で独自実装を行う必要がありました。

また、ユーザーがコンボボックスに文字を入力しても input イベントが発火しないため、<wa-input> やネイティブの <input> と異なる挙動になっていました。この非一貫性は、フォームライブラリや入力監視処理との統合を複雑にしていました。

さらに allow-custom-value が設定されている環境では、ブラー時にカスタム値がコミットされない問題や、入力をクリアしてフォーカスを外すと直前の選択値が復元されてしまう問題も存在していました。

技術的な変更

今回の変更は、新機能の追加・イベント対応・バグ修正の3軸で構成されます。

allow-create 属性と wa-create イベントの追加が中心的な変更です。既存のどのオプションにもマッチしないテキストを入力すると、ドロップダウンに「Create \"[value]\"」という選択肢が出現します。これを選ぶと実際の <wa-option> がDOMに追加され、キャンセル可能な wa-create イベントが発火します。このイベントはカスタムハンドリングにも対応しており、独自のオプション追加ロジックを割り込ませることが可能です。

wa-create イベントの型定義は src/events/create.ts として新設されました。

export class WaCreateEvent extends Event {
  readonly detail;

  constructor(detail: WaCreateEventDetail) {
    super('wa-create', { bubbles: true, cancelable: true, composed: true });
    this.detail = detail;
  }
}

export interface WaCreateEventDetail {
  inputValue: string;
}

declare global {
  interface GlobalEventHandlersEventMap {
    'wa-create': WaCreateEvent;
  }
}

GlobalEventHandlersEventMap への登録により、TypeScript環境でも addEventListener('wa-create', ...) が型安全に利用できます。events.ts にも WaCreateEvent のre-exportが追加されており、他のイベント型と同様に公開APIとして扱われます。

input イベントの発火 は、コンボボックスへの入力時に標準的な input イベントを発火させることで、<wa-input> やネイティブフォームコントロールとの一貫性を確保します。これにより、フォームライブラリや入力監視処理が <wa-combobox> に対しても同じコードで機能します。

翻訳対応として、「Create \"[value]\"」というラベルの createOption キーが全30言語以上の翻訳ファイルに追加されました。各言語ごとに value => \...`形式の関数として定義されており、入力値を埋め込んで表示できます。日本語訳は「${value}」を作成、フランス語訳はCréer « ${value} »` のように、各言語の引用符スタイルも適切に反映されています。

設計判断

wa-create イベントをキャンセル可能(cancelable)にした設計が注目されます。{ cancelable: true } を指定することで、イベントハンドラ内で event.preventDefault() を呼び出せば、デフォルトのDOM追加処理を抑止できます。これにより、バリデーションや非同期処理を挟みながらオプション追加の可否を制御するパターンが実現可能です。

composed: true の指定も意図的な判断です。Shadow DOMの境界を越えてイベントが伝播するため、コンポーネントをラップしたカスタム要素からでもイベントリスナーで捕捉できます。

ビルドスクリプト(build.js)でも小さな改善が加えられており、getVersion の非同期関数が同期的なトップレベルの await に変更されています。ora スピナーの初期化もオプションなしのシンプルな呼び出しになり、バージョン情報は chalk を使ったカラー出力に統一されました。

まとめ

本PRは <wa-combobox> を「選ぶだけ」のコンポーネントから「作って選べる」コンポーネントへと拡張し、タグ入力のようなリッチなUXパターンへの対応を実現しています。キャンセル可能なイベントと全言語対応の翻訳キーを同時に整備したことで、国際化対応アプリケーションでも即座に組み込める設計になっています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
a7e20c9e

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「総論→各論→結論」の構成が明確です。リード文、背景、技術的な変更、設計判断、まとめの全要素が適切に配置されており、理想的な記事構成です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライトの形式(```typescript:path/to/file.ts)やPRへのリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

イベントの cancelable や composed の意味、Shadow DOM との関連性など、専門知識を持つエンジニアを対象とした適切な技術レベルで記述されています。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論から各論へと展開され、各パラグラフはトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が非常によく守られており、高い可読性を実現しています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内で引用されている`packages/webawesome/src/events/create.ts`のコードは、提供されたDiff情報と完全に一致しており、正確です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`allow-create`、`wa-create`、`cancelable`、`composed`といった技術用語が正確かつ文脈に沿って適切に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

イベントのキャンセル可能性やShadow DOMの境界を越える挙動、ビルドスクリプトの改善点など、技術的な説明はすべてDiffの内容と整合性が取れており、正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内の主張(新機能追加、イベント発火、バグ修正、翻訳対応)はすべてPRのDescriptionやDiff(特にchangelog.md)で裏付けられており、ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2166)が正しく記載されています。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事のタイトルは、PRのタイトル「Combobox updates」の要点をより具体的に表しており、内容と完全に一致しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PR情報に含まれないバージョンのサポート状況やリリース日程などの外部知識の持ち込みはなく、提供された情報源に忠実です。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

PRの事実関係を歪めるような不正確な時間表現(「既に」「まもなく」など)は使用されていません。