Dropdown menu
ボタンの背後に、操作とオプションをまとめたメニューです。グループ、サブメニュー、チェックボックス項目、ラジオ項目、ショートカットに対応します。
pnpm dlx shadcn@latest add https://hextaui.com/r/dropdown-menu.jsonコンポーネント、HextaUIのテーマトークン、依存するHextaUIコンポーネントを追加します。
まだ追加していない場合は、グローバルCSSにテーマトークンを追加してください。
依存関係をインストールします。
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cn次のコードをコピーしてプロジェクトに貼り付けてください。
components/ui/dropdown-menu.tsx インポートパスは、お使いのプロジェクト構成に合わせて更新してください。
セーフエリア
サブメニューのトリガーからサブメニューに向かって斜めに動くと、兄弟のトリガーを横切ります。セーフエリアは、ポインターがサブメニューに向かっている間、サブメニューを開いたままにします。showSafeArea をオンにすると実際に確認できます。ドットはエリア内では緑に、サブメニューが切り替わる位置では赤になります。
チェックボックス
<DropdownMenuCheckboxItem /> は設定を切り替え、メニューを開いたままにするため、続けて複数を変更できます。チェックマークはポップではなく、描画されて現れ、消えます。
Radio group
1 つの選択肢を選ぶには、<DropdownMenuRadioItem /> を <DropdownMenuRadioGroup /> で囲みます。グループ内のラベルが、スクリーンリーダー向けにグループの名前になります。
右側にチェック
チェックボックスとラジオの項目に indicator="end" を設定すると、チェックをインデントせずにラベルの後ろに表示します。各選択肢の下に説明があるピッカーに向いています。
select 風
メニューはトリガーより狭くなりません。1 つ選んだらメニューも閉じたい場合は、ラジオ項目に closeOnClick を設定します。
行アクション
1 つのメニューがすべての行に対応します。createDropdownMenuHandle でハンドルを作成し、payload とともに各トリガーに渡し、メニュー内で payload を読み取ります。Delete は alert dialog に引き継がれます。
制御
open と onOpenChange を渡します。第 2 引数は、トリガーの押下、項目の押下、Escape など、メニューが変化した理由を示します。closeOnClick={false} の項目は、開いたままにします。
ホバーで開く
トリガーの openOnHover は、delay 後にメニューを開き、closeDelay 後に閉じます。クリックとキーボードも引き続き使えるため、タッチやキーボードのユーザーが締め出されることはありません。
無効
無効なトリガーは開きません。無効な項目は表示されたままですが、矢印キーではスキップされます。
長いコンテンツ
ラベルはメニューを 20rem より広げず折り返され、区切りのない文字列はどこでも改行され、ショートカットは 1 行目にとどまります。
スクロール
すべての項目が収まらない場合、メニューはビューポート内でスクロールし、ハイライトされた項目は表示位置までスクロールされます。
シートの中
メニューはシートの上に重なります。Escape はまずメニューを、次にシートを閉じます。
右から左
メニュー、サブメニューの山形アイコン、サブメニューの側は、トリガーの方向に従います。ショートカットは、左から右の順序を保ちます。
| キー | アクション |
|---|---|
| EnterSpace↓ | トリガーでは、メニューを開き、最初の項目をハイライトします。 |
| ↓ | 次の項目をハイライトし、末尾では先頭に回り込みます。 |
| ↑ | 前の項目をハイライトし、先頭では末尾に回り込みます。 |
| Home | 最初の項目をハイライトします。 |
| End | 最後の項目をハイライトします。 |
| EnterSpace | ハイライト中の項目を実行します。チェックボックスとラジオの項目は切り替わり、メニューは開いたままになります。 |
| → | ハイライト中のサブメニューを開き、その中に移動します。右から左のレイアウトでは ←。 |
| ← | 現在のサブメニューを閉じ、そのトリガーに戻ります。右から左のレイアウトでは →。 |
| Esc | 現在のメニューを閉じ、そのトリガーにフォーカスを戻します。サブメニューでは、そのサブメニューだけが閉じます。 |
| A–Z | その文字で始まる次の項目をハイライトします。 |
- トリガーはメニューボタンとして通知され、メニューが閉じるとフォーカスが戻ります。
- 行アクションの例のように、アイコンのみのトリガーには
aria-labelを付けてください。 <DropdownMenuShortcut />は視覚的なラベルのみです。キーのバインドは自分で行ってください。- モーションの低減が有効な場合、メニューは拡大縮小せずにフェードし、項目の点滅はスキップされます。
Base UI の menu をベースにしています。各パーツは、ラップしているプリミティブの props を受け付けます。
| プロパティ | 型 | デフォルト |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
showSafeAreaメニューが開いている間、サブメニューのセーフエリアを描画します。デバッグとデモ用です。 | boolean | false |
onOpenChangedetails.reason は、変更の原因を示します。 | (open: boolean, details) => void | – |
modal開いている間、ページのスクロールをロックし、外側のクリックをブロックします。 | boolean | true |
loopFocus矢印キーを、どちらの端でも反対側に回り込ませます。 | boolean | true |
handle分離されたトリガーをこのメニューに接続します。 | DropdownMenuHandle<Payload> | – |
children開いたトリガーの payload を読み取るには、関数形式を使います。 | ReactNode | ({ payload }) => ReactNode | – |
disabled | boolean | false |
| プロパティ | 型 | デフォルト |
|---|---|---|
openOnHover | boolean | false |
delayホバーしてからメニューが開くまでのミリ秒。 | number | 100 |
closeDelayホバーで開いたメニューが閉じるまでのミリ秒。 | number | 0 |
handle | DropdownMenuHandle<Payload> | – |
payloadこのトリガーがメニューを開いたときに、メニューに渡されます。 | Payload | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <button> |
| 属性 | 説明 |
|---|---|
data-slot="dropdown-menu-trigger" | CSSでトリガーを指定します。 |
data-popup-open | メニューが開いている間存在します。 |
data-pressed | トリガーが押されている間存在します。 |
data-disabled | トリガーが無効なときに付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" |
align | "start" | "center" | "end" | "start" |
sideOffset | number | 4 |
alignOffset | number | 0 |
collisionPaddingメニューとビューポートの端の間に確保される空間。 | number | Rect | 8 |
anchorトリガーではなく、別の要素を基準に配置します。 | Element | RefObject | VirtualElement | – |
sticky | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| 属性 | 説明 |
|---|---|
data-slot="dropdown-menu-content" | CSS でメニューを指定します。 |
data-open | メニューが開いている間、付与されます。 |
data-starting-style | メニューが表示アニメーションをしている間、付与されます。 |
data-ending-style | メニューが非表示アニメーションをしている間、付与されます。 |
data-side | 衝突の処理後にメニューが決まった側。 |
data-align | 最終的に決まった揃え位置。 |
data-chosen | 項目がクリックされた後に付与されるため、メニューは閉じる前に、項目の確定の点滅を待ちます。 |
--anchor-width | トリガーの幅。メニューは少なくともこの幅になります。 |
--available-height | ビューポートに残っている余白。長いメニューはその中でスクロールします。 |
--transform-origin | トリガーの隣にある、スケールアニメーションの拡大の起点。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
variant | "default" | "destructive" | "default" |
inset項目をインデントして、チェックボックス項目と揃えます。 | boolean | false |
closeOnClick | boolean | true |
onClick | (event) => void | – |
labelchildren がプレーンテキストでない場合に、先頭文字検索(type-ahead)に使われるテキスト。 | string | – |
disabled | boolean | false |
renderrender={<a href="…" />} でリンクをレンダリングします。 | ReactElement | (props, state) => ReactElement | <div> |
| 属性 | 説明 |
|---|---|
data-slot="dropdown-menu-item" | CSSで項目を指定します。 |
data-variant | 現在のバリアント。 |
data-highlighted | ポインターまたはキーボードで項目がハイライトされている間、付与されます。 |
data-disabled | 項目が無効のときに存在します。 |
data-chosen | クリックされた直後、点滅している間、その項目に付与されます。 |
data-inset | inset が設定されているときに付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
checked | boolean | – |
defaultChecked | boolean | false |
onCheckedChange | (checked: boolean, details) => void | – |
closeOnClick | boolean | false |
inset | boolean | false |
indicator | "start" | "end" | "start" |
disabled | boolean | false |
| 属性 | 説明 |
|---|---|
data-slot="dropdown-menu-checkbox-item" | CSS でチェックボックス項目を指定します。 |
data-checked | チェックされているときに付与されます。 |
data-unchecked | チェックされていないときに付与されます。 |
data-highlighted | ポインターまたはキーボードで項目がハイライトされている間、付与されます。 |
data-disabled | 項目が無効のときに存在します。 |
data-chosen | クリックされた直後、点滅している間、その項目に付与されます。 |
data-inset | inset が設定されているときに付与されます。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
value | Value | – |
defaultValue | Value | – |
onValueChange | (value: Value, details) => void | – |
disabled | boolean | false |
| プロパティ | 型 | デフォルト |
|---|---|---|
value | Value | – |
closeOnClick | boolean | false |
inset | boolean | false |
indicator | "start" | "end" | "start" |
disabled | boolean | false |
| 属性 | 説明 |
|---|---|
data-slot="dropdown-menu-radio-item" | CSS でラジオ項目を指定します。 |
data-checked | 選択された項目に付与されます。 |
data-unchecked | 他の項目に付与されます。 |
data-highlighted | ポインターまたはキーボードで項目がハイライトされている間、付与されます。 |
data-disabled | 項目が無効のときに存在します。 |
data-chosen | クリックされた直後、点滅している間、その項目に付与されます。 |
data-inset | inset が設定されているときに付与されます。 |
関連する項目をグループ化します。その内側の <DropdownMenuLabel /> が、グループのアクセシブルな名前になります。
| プロパティ | 型 | デフォルト |
|---|---|---|
inset | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
グループ間の区切り線。separator として通知されます。
| プロパティ | 型 | デフォルト |
|---|---|---|
dirショートカットは、右から左のメニューでもキーの順序を保ちます。 | "ltr" | "rtl" | "ltr" |
| プロパティ | 型 | デフォルト |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
onOpenChange | (open: boolean, details) => void | – |
closeParentOnEscEscape で、このサブメニューだけでなくメニュー全体を閉じます。 | boolean | false |
| プロパティ | 型 | デフォルト |
|---|---|---|
inset | boolean | false |
disabled | boolean | false |
delayホバーしてからサブメニューが開くまでのミリ秒。 | number | 100 |
closeDelay | number | 0 |
| 属性 | 説明 |
|---|---|
data-slot="dropdown-menu-sub-trigger" | CSS でサブメニューのトリガーを指定します。 |
data-popup-open | サブメニューが開いている間、付与されます。 |
data-highlighted | ハイライトされている間存在します。 |
| プロパティ | 型 | デフォルト |
|---|---|---|
sideOffset | number | 0 |
alignOffset | number | -4 |
render | ReactElement | (props, state) => ReactElement | <div> |
| 属性 | 説明 |
|---|---|
data-slot="dropdown-menu-sub-content" | CSS でサブメニューを指定します。 |
data-open | メニューが開いている間、付与されます。 |
data-starting-style | メニューが表示アニメーションをしている間、付与されます。 |
data-ending-style | メニューが非表示アニメーションをしている間、付与されます。 |
data-side | 衝突の処理後にメニューが決まった側。 |
data-align | 最終的に決まった揃え位置。 |
data-chosen | 項目がクリックされた後に付与されるため、メニューは閉じる前に、項目の確定の点滅を待ちます。 |
--available-height | ビューポートに残っている余白。長いメニューはその中でスクロールします。 |
--transform-origin | トリガーの隣にある、スケールアニメーションの拡大の起点。 |
- Alert dialog破壊的または重要な操作のための確認ダイアログです。非同期処理を待ち、スマートフォンではボトムシートになります。
- Commandインラインまたは⌘Kパレットとして使える、検索可能な操作リストです。ページ、ショートカット、一致箇所のハイライトに対応します。
- Context menu右クリックまたは長押しで開く操作メニューです。サブメニュー、チェックボックス項目、ラジオ項目に対応し、タッチでは長押しのフィードバックを返します。
- Dialogフォームや集中して行う作業のための、ページ上のウィンドウです。固定のヘッダーとフッター、入れ子に対応し、スマートフォンではスワイプできるボトムシートになります。
- Drawer任意の端からスライドインし、指に追従するパネルです。スナップポイント、実際に使えるハンドル、重なっていく入れ子のドロワーに対応します。
- Hover cardリンクにホバーまたはフォーカスすると開くプレビューカードです。視覚で閲覧するユーザーがさっと確認できる内容向けです。
使用しているブロック
Dropdown menu の上に構築されるブロック。
- Prompt Input最初は静かな1行で、入力に合わせてカードへ広がり、会話が始まると下へ移動するチャット入力欄です。Enterで送信でき、日本語や中国語の入力でも安全です。ファイルは貼り付け、ドロップ、選択でき、プレビュー、進捗、再試行に対応します。@でファイルを追加し、/でコマンドをカーソル位置のメニューから実行できます。数字キーで選べるモデルピッカー、Maxで動き出す推論量スライダー、コンテキストリング、リアルタイム波形つきの音声入力、ツールチップ、返信のストリーミング中に入力したメッセージのキュー、再読み込みしても残る下書きを備えています。
- API keysOpenAIやAnthropicのコンソールのような、AIプロダクトのAPIキーのページです。スコープ付きの権限と有効期限を持つキーを作成し、シークレットは一度だけ表示され、コピーで確認でき、取り消しは元に戻せ、その場で名前を変更でき、猶予期間つきでローテーションでき、キーごとの使用量を確認できます。
- Artifactモデルが作成したものを表示する、AIチャットの横のパネルです。Webページ、SVG、ドキュメント、コードがリアルタイムでストリーミングされ、その後サンドボックス化されたプレビューに切り替わります。比較して復元できるバージョン、サイズを変更できる分割、スマートフォンでのボトムシートを備えています。
- Chat Sidebarチャットアプリ向けのサイドバーです。上部にロゴ、検索、New chat、その下に独自のリンク、ピン留めされたチャット、チャットを表示するために展開するプロジェクト、日ごとにグループ化された最近のチャットを配置します。行にはホバーメニューと右クリックメニュー、インラインでの名前変更、取り消しできる削除、リアルタイムの返信状態があります。