Menu
Menuは、一般的なドロップダウンメニューを表示するコンポーネントです。
<Menu.Root>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="naruto">うずまきナルト</Menu.Item>
<Menu.Item value="sasuke">うちはサスケ</Menu.Item>
<Menu.Item value="sakura">春野サクラ</Menu.Item>
</Menu.Content>
</Menu.Root>
使い方
import { Menu } from "@yamada-ui/react"
import { Menu } from "@/components/ui"
import { Menu } from "@workspaces/ui"
<Menu.Root>
<Menu.Trigger />
<Menu.ContextTrigger />
<Menu.Anchor />
<Menu.Content>
<Menu.Header />
<Menu.Group>
<Menu.Item>
<Menu.Label />
<Menu.Indicator />
<Menu.Command />
</Menu.Item>
</Menu.Group>
<Menu.Separator />
<Menu.OptionGroup>
<Menu.OptionItem />
</Menu.OptionGroup>
<Menu.Footer />
</Menu.Content>
</Menu.Root>
itemsを使う
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)
サイズを変更する
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<HStack>
<For each={["sm", "md", "lg"]}>
{(size) => (
<Menu.Root key={size} size={size}>
<Menu.Trigger>
<Button>{toTitleCase(size)}</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)}
</For>
</HStack>
)
選択時のイベントをハンドルする
選択時のイベントをハンドルする場合は、onSelectを使用します。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root onSelect={(value) => console.log("selected", value)}>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)
区切り線を追加する
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
{ type: "separator" },
{ label: "大蛇丸", value: "orochimaru" },
{ label: "自來也", value: "pervy-sage" },
{ label: "綱手", value: "tsunade" },
],
[],
)
return (
<HStack>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with items</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with composition</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="naruto">うずまきナルト</Menu.Item>
<Menu.Item value="sasuke">うちはサスケ</Menu.Item>
<Menu.Item value="sakura">春野サクラ</Menu.Item>
<Menu.Separator />
<Menu.Item value="orochimaru">大蛇丸</Menu.Item>
<Menu.Item value="pervy-sage">自來也</Menu.Item>
<Menu.Item value="tsunade">綱手</Menu.Item>
</Menu.Content>
</Menu.Root>
</HStack>
)
グループ化する
const items = useMemo<Menu.Item[]>(
() => [
{
items: [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
label: "第七班",
},
{
items: [
{ label: "大蛇丸", value: "orochimaru" },
{ label: "自來也", value: "pervy-sage" },
{ label: "綱手", value: "tsunade" },
],
label: "伝説の三忍",
},
],
[],
)
return (
<HStack>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with items</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with composition</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Group label="第七班">
<Menu.Item value="naruto">うずまきナルト</Menu.Item>
<Menu.Item value="sasuke">うちはサスケ</Menu.Item>
<Menu.Item value="sakura">春野サクラ</Menu.Item>
</Menu.Group>
<Menu.Separator />
<Menu.Group label="伝説の三忍">
<Menu.Item value="orochimaru">大蛇丸</Menu.Item>
<Menu.Item value="pervy-sage">自來也</Menu.Item>
<Menu.Item value="tsunade">綱手</Menu.Item>
</Menu.Group>
</Menu.Content>
</Menu.Root>
</HStack>
)
アイコンを表示する
const items = useMemo<Menu.Item[]>(
() => [
{
label: (
<>
<Menu.Indicator>
<PlusIcon />
</Menu.Indicator>
New Tab
</>
),
value: "tab",
},
{
label: (
<>
<Menu.Indicator>
<SquareArrowOutUpRightIcon />
</Menu.Indicator>
New Window
</>
),
value: "window",
},
{
label: (
<>
<Menu.Indicator>
<SquarePenIcon />
</Menu.Indicator>
New File
</>
),
value: "file",
},
],
[],
)
return (
<HStack>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with items</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with composition</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="tab">
<Menu.Indicator>
<PlusIcon />
</Menu.Indicator>
New Tab
</Menu.Item>
<Menu.Item value="window">
<Menu.Indicator>
<SquareArrowOutUpRightIcon />
</Menu.Indicator>
New Window
</Menu.Item>
<Menu.Item value="file">
<Menu.Indicator>
<SquarePenIcon />
</Menu.Indicator>
New File
</Menu.Item>
</Menu.Content>
</Menu.Root>
</HStack>
)
コマンドを表示する
const items = useMemo<Menu.Item[]>(
() => [
{
label: (
<>
New Tab
<Menu.Command>⌘T</Menu.Command>
</>
),
value: "tab",
},
{
label: (
<>
New Window
<Menu.Command>⌘N</Menu.Command>
</>
),
value: "window",
},
{
label: (
<>
New File
<Menu.Command>⌘O</Menu.Command>
</>
),
value: "file",
},
],
[],
)
return (
<HStack>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with items</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with composition</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="tab">
New Tab
<Menu.Command>⌘T</Menu.Command>
</Menu.Item>
<Menu.Item value="window">
New Window
<Menu.Command>⌘N</Menu.Command>
</Menu.Item>
<Menu.Item value="file">
New File
<Menu.Command>⌘O</Menu.Command>
</Menu.Item>
</Menu.Content>
</Menu.Root>
</HStack>
)
選択可能な項目を設定する
const [value, setValue] = useState<string[]>(["naruto"])
const items = useMemo<Menu.Item[]>(
() => [
{
type: "checkbox",
items: [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
{ label: "はたけカカシ", value: "kakashi", disabled: true },
],
value,
onChange: setValue,
},
],
[value],
)
return (
<HStack>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with items</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
<Menu.Root>
<Menu.Trigger>
<Button>Menu with composition</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.OptionGroup type="checkbox" value={value} onChange={setValue}>
<Menu.OptionItem value="naruto">うずまきナルト</Menu.OptionItem>
<Menu.OptionItem value="sasuke">うちはサスケ</Menu.OptionItem>
<Menu.OptionItem value="sakura">春野サクラ</Menu.OptionItem>
<Menu.OptionItem disabled value="kakashi">
はたけカカシ
</Menu.OptionItem>
</Menu.OptionGroup>
</Menu.Content>
</Menu.Root>
</HStack>
)
ネストさせる
<Menu.Root>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="naruto">うずまきナルト</Menu.Item>
<Menu.Item value="sasuke">うちはサスケ</Menu.Item>
<Menu.Item value="sakura">春野サクラ</Menu.Item>
<Menu.Root>
<Menu.Trigger>
<Menu.Item>Settings</Menu.Item>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="extensions">Extensions</Menu.Item>
<Menu.Item value="theme">Theme</Menu.Item>
<Menu.Item value="tasks">User Tasks</Menu.Item>
</Menu.Content>
</Menu.Root>
</Menu.Content>
</Menu.Root>
コンテキストメニューを使用する
<Menu.Root>
<Menu.ContextTrigger>
<Center
borderStyle="dashed"
borderWidth="1px"
h="xs"
p="md"
rounded="l2"
w="full"
>
<Text>Right Click Here</Text>
</Center>
</Menu.ContextTrigger>
<Menu.Content>
<Menu.Item value="copy">Copy</Menu.Item>
<Menu.Item value="paste">Paste</Menu.Item>
<Menu.Item value="delete">Delete</Menu.Item>
</Menu.Content>
</Menu.Root>
別の要素を参照して表示する
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root>
<HStack>
<Menu.Anchor>
<Center borderWidth="1px" h="10" px="3" rounded="l2">
Here display Popover
</Center>
</Menu.Anchor>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
</HStack>
<Menu.Content items={items} />
</Menu.Root>
)
選択時の閉じる動作を無効にする
選択時の閉じる動作を無効にする場合は、closeOnSelectをfalseに設定します。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root closeOnSelect={false}>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)
内部状態にアクセスする
内部状態にアクセスする場合は、Menu.Rootのchildrenに関数を渡します。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root>
{({ open }) => (
<>
<Menu.Trigger>
<Button>{open ? "Close" : "Open"} Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</>
)}
</Menu.Root>
)
"use client"をファイルの上部に追加する必要があります。初回のフォーカスを設定する
初回のフォーカスを設定する場合は、initialFocusRefにRefを渡します。
const ref = useRef<HTMLDivElement>(null)
return (
<Menu.Root initialFocusRef={ref}>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content>
<Menu.Item value="status">Set Status</Menu.Item>
<Menu.Item ref={ref} value="profile">
Edit Profile
</Menu.Item>
<Menu.Item value="preferences">Preferences</Menu.Item>
</Menu.Content>
</Menu.Root>
)
"use client"をファイルの上部に追加する必要があります。配置を変更する
配置を変更する場合は、placementに"start"や"end-end"などを設定します。デフォルトでは、"end-start"が設定されています。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<HStack>
<For
each={[
"start",
"start-start",
"start-end",
"end",
"end-start",
"end-end",
]}
>
{(placement) => (
<Menu.Root key={placement} placement={placement}>
<Menu.Trigger>
<Button>{toTitleCase(placement)}</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)}
</For>
</HStack>
)
アニメーションを変更する
アニメーションを変更する場合は、animationSchemeに"inline-start"や"block-end"などを設定します。デフォルトでは、"scale"が設定されています。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<HStack>
<For
each={["scale", "block-end", "block-start", "inline-start", "inline-end"]}
>
{(animationScheme) => (
<Menu.Root key={animationScheme} animationScheme={animationScheme}>
<Menu.Trigger>
<Button>{toTitleCase(animationScheme)}</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)}
</For>
</HStack>
)
オフセットを変更する
オフセットを変更する場合は、gutterまたはoffsetに値を設定します。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<HStack>
<Menu.Root gutter={32}>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
<Menu.Root offset={[16, 16]}>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
</HStack>
)
継続時間を変更する
所要時間を変更する場合は、durationに数値(秒)を設定します。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root duration={0.4}>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)
外側のクリック時に閉じない
外側のクリック時に閉じない場合は、closeOnBlurをfalseに設定します。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root closeOnBlur={false}>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)
項目を無効にする
項目を無効にする場合は、disabledをtrueに設定します。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke", disabled: true },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)
ヘッダーやフッターを追加する
ヘッダーやフッターを追加する場合は、Menu.ContentのheaderまたはfooterにReactNodeを設定します。
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
{ label: "大蛇丸", value: "orochimaru" },
{ label: "自來也", value: "pervy-sage" },
{ label: "綱手", value: "tsunade" },
],
[],
)
return (
<Menu.Root>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content
header="キャラクター"
footer="キャラクター"
items={items}
maxH="2xs"
/>
</Menu.Root>
)
制御する
const { open, onOpen, onClose } = useDisclosure()
const items = useMemo<Menu.Item[]>(
() => [
{ label: "うずまきナルト", value: "naruto" },
{ label: "うちはサスケ", value: "sasuke" },
{ label: "春野サクラ", value: "sakura" },
],
[],
)
return (
<Menu.Root open={open} onOpen={onOpen} onClose={onClose}>
<Menu.Trigger>
<Button>Menu</Button>
</Menu.Trigger>
<Menu.Content items={items} />
</Menu.Root>
)
"use client"をファイルの上部に追加する必要があります。Props
アクセシビリティ
Menuは、アクセシビリティに関してWAI-ARIA - Menu and Menubar PatternおよびWAI-ARIA - Menu Button Patternに従います。
キーボード操作
| キー | 説明 | 状態 |
|---|---|---|
Space, Enter | メニューを開き、無効ではない最初の項目をフォーカスします。 | - |
| メニュー内である場合はフォーカスされている項目をアクティブにして、すべてのメニューを閉じます。 | closeOnSelect={true} | |
ArrowRight | サブメニューのトリガーである場合はサブメニューを開き、無効ではない最初の項目をフォーカスします。 | subMenuDirection="end" |
| サブメニュー内である場合はサブメニューを閉じ、サブメニューのトリガーにフォーカスします。 | subMenuDirection="start" | |
ArrowLeft | サブメニューのトリガーである場合はサブメニューを開き、無効ではない最初の項目をフォーカスします。 | subMenuDirection="start" |
| サブメニュー内である場合はサブメニューを閉じ、サブメニューのトリガーにフォーカスします。 | subMenuDirection="end" | |
ArrowUp | メニューを開き、無効ではない最後の項目をフォーカスします。メニュー内である場合は無効ではない前の項目をフォーカスします。最初の項目の場合は無効ではない最後の項目をフォーカスします。 | - |
ArrowDown | メニューを開き、無効ではない最初の項目をフォーカスします。メニュー内である場合は無効ではない次の項目をフォーカスします。最後の項目の場合は無効ではない最初の項目をフォーカスします。 | - |
Home | メニュー内である場合は無効ではない最初の項目をフォーカスします。 | - |
End | メニュー内である場合は無効ではない最後の項目をフォーカスします。 | - |
Escape | メニューを閉じてトリガーにフォーカスします。 | closeOnEsc={true} |
ARIAロールと属性
| コンポーネント | ロールと属性 | 使い方 |
|---|---|---|
Menu.Trigger | role="button" | ボタンであることを示します。 |
aria-controls | メニューが開いている場合は関連したMenu.Contentのidを設定し、閉じている場合はundefinedを設定します。 | |
aria-disabled | disabledが設定されている場合は"true"を設定します。 | |
aria-expanded | メニューが開いている場合は"true"を設定し、閉じている場合は、"false"を設定します。 | |
aria-haspopup="menu" | メニューが存在することを示します。 | |
Menu.ContextTrigger | role="application" | アプリケーションであることを示します。 |
aria-controls | メニューが開いている場合は関連したMenu.Contentのidを設定し、閉じている場合はundefinedを設定します。 | |
aria-disabled | disabledが設定されている場合は"true"を設定します。 | |
aria-expanded | メニューが開いている場合は"true"を設定し、閉じている場合は、"false"を設定します。 | |
aria-haspopup="menu" | メニューが存在することを示します。 | |
Menu.Content | role="menu" | メニューであることを示します。 |
aria-activedescendant | フォーカスされた項目のidを設定します。 | |
aria-hidden | メニューが開いている場合は"false"を設定し、閉じている場合は"true"を設定します。 | |
aria-labelledby | 関連したMenu.TriggerまたはMenu.ContextTriggerのidを設定します。 | |
Menu.Label | role="presentation" | プレゼンテーションであることを示します。 |
Menu.Group | role="group" | グループであることを示します。 |
aria-labelledby | 関連したMenu.Labelのidを設定します。 | |
Menu.Item | role="menuitem" | メニュー項目であることを示します。 |
aria-disabled | disabledが設定されている場合は"true"を設定します。 | |
Menu.OptionItem | role | Menu.OptionGroupのtypeが"radio"に設定されている場合は"menuitemradio"を設定し、"checkbox"に設定されている場合は"menuitemcheckbox"を設定します。 |
Menu.Separator | role="separator" | セパレーターであることを示します。 |
類似のコンポーネント
Select
Selectは、ユーザーがオプションのリストから値を選択するために使用されるコンポーネントです。
NativePopover
NativePopoverは、HTML Popover APIを使用して要素の周りにフローティングして情報を表示するコンポーネントです。
Autocomplete
Autocompleteは、ユーザーのテキスト入力に応じて候補を表示するために使用されるコンポーネントです。
Tooltip
Tooltipは、要素の補足など短い情報を表示するコンポーネントです。
Popover
Popoverは、要素の周りにフローティングして情報を表示するコンポーネントです。
Tabs
Tabsは、異なる表示領域を切り替えるコンポーネントです。
Modal
Modalは、主要なコンテンツに重ねて表示され、ユーザーの注意を情報のみに集中させるコンポーネントです。
Drawer
Drawerは、画面の端から表示されるパネルのコンポーネントです。
使用しているコンポーネント・フック
useDescendants
useDescendantsは、子要素を管理するためのカスタムフックです。
useDisclosure
useDisclosureは、一般的な開閉や切り替えのシナリオを処理するのに役立つカスタムフックです。Modal、Dialog、Drawerなどのコンポーネントを制御するために使用できます。