# Menu
URL: /react/components/menu
Source: https://github.com/daangn/seed-design/blob/dev/docs/content/react/components/menu.mdx
사용자가 취할 수 있는 선택지나 액션 리스트를 제공하는 컴포넌트입니다.
사용 가능 버전: @seed-design/react@2.0.0, @seed-design/css@2.0.0
## Preview
```tsx
import {
IconPencilLine,
IconPlusLine,
IconTrashcanLine,
} from "@karrotmarket/react-monochrome-icon";
import { ActionButton } from "seed-design/ui/action-button";
import {
MenuContent,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuRoot,
MenuTrigger,
} from "seed-design/ui/menu";
export default function MenuPreview() {
return (
열기
작업
} />
}
/>
}
/>
);
}
```
## Installation
- npm: npx @seed-design/cli@latest add ui:menu
- pnpm: pnpm dlx @seed-design/cli@latest add ui:menu
- yarn: yarn dlx @seed-design/cli@latest add ui:menu
- bun: bun x @seed-design/cli@latest add ui:menu
## Usage
Menu는 아래와 같은 구조로 구성됩니다.
```tsx
import {
MenuRoot,
MenuTrigger,
MenuContent,
MenuGroup,
MenuGroupLabel,
MenuItem,
} from "seed-design/ui/menu";
```
```tsx
...
그룹 제목
```
- `MenuRoot`: 메뉴의 상태(열림/닫힘)와 위치를 관리합니다.
- `MenuTrigger`: 클릭 시 메뉴를 열고 닫는 트리거입니다.
- `MenuAnchor`: 메뉴의 위치 기준점만 제공하며, 열고 닫는 동작은 포함하지 않습니다. 트리거 동작을 직접 제어해야 하는 경우에 `MenuTrigger` 대신 사용합니다.
- `MenuContent`: 메뉴 항목들을 감싸는 플로팅 컨테이너입니다.
- `MenuGroup`: 관련된 항목들을 그룹으로 묶습니다. 모든 `MenuItem`은 `MenuGroup` 안에 있어야 합니다.
- `MenuGroupLabel`: 그룹의 제목을 표시합니다.
- `MenuItem`: 개별 메뉴 항목입니다.
## Props
### `MenuRoot`
### `MenuTrigger`
### `MenuAnchor`
### `MenuContent`
### `MenuGroup`
### `MenuGroupLabel`
### `MenuItem`
## Examples
### Trigger
``는 `aria-haspopup="menu"` 속성을 설정하고, Menu의 `open` 상태에 따라 `aria-expanded` 속성을 자동으로 설정합니다. 이 속성은 스크린 리더와 같은 보조 기술에 유용합니다.
## Preview
```tsx
import {
IconPencilLine,
IconPlusLine,
IconTrashcanLine,
} from "@karrotmarket/react-monochrome-icon";
import { ActionButton } from "seed-design/ui/action-button";
import {
MenuContent,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuRoot,
MenuTrigger,
} from "seed-design/ui/menu";
export default function MenuPreview() {
return (
열기
작업
} />
}
/>
}
/>
);
}
```
### Size
`size`로 MenuRoot의 크기를 정합니다. (default: `medium`)
`responsive`는 화면 너비에 따라 size가 자동으로 전환되는 값입니다. 여러 화면 너비를 함께 지원하는 제품에서 `size=responsive`를 사용하여 대응합니다.
```tsx
import { IconPencilLine, IconPlusLine } from "@karrotmarket/react-monochrome-icon";
import { HStack } from "@seed-design/react";
import { ActionButton } from "seed-design/ui/action-button";
import {
MenuContent,
MenuGroup,
MenuGroupLabel,
MenuItem,
MenuRoot,
MenuTrigger,
} from "seed-design/ui/menu";
export default function MenuSize() {
return (
Medium
작업
} />
} />
Small
작업
} />
} />
Responsive
작업
} />
} />
);
}
```
### With Description
`MenuItem`의 `description` prop을 사용하여 항목에 부가 설명을 추가합니다.
```tsx
import {
IconArrowUpBracketDownLine,
IconPencilLine,
IconPlusLine,
} from "@karrotmarket/react-monochrome-icon";
import { ActionButton } from "seed-design/ui/action-button";
import { MenuContent, MenuGroup, MenuItem, MenuRoot, MenuTrigger } from "seed-design/ui/menu";
export default function MenuWithDescription() {
return (
열기
}
/>
}
/>
}
/>
);
}
```
### Tone
`MenuItem`의 `tone` prop으로 항목의 톤을 설정합니다.
```tsx
import {
IconPencilLine,
IconPlusLine,
IconTrashcanLine,
} from "@karrotmarket/react-monochrome-icon";
import { ActionButton } from "seed-design/ui/action-button";
import { MenuContent, MenuGroup, MenuItem, MenuRoot, MenuTrigger } from "seed-design/ui/menu";
export default function MenuTone() {
return (
열기
} />
} />
} />
);
}
```
### Disabled Items
`MenuItem`의 `disabled` prop을 사용하여 특정 항목을 비활성화합니다.
```tsx
import {
IconArrowUpBracketDownLine,
IconPencilLine,
IconPlusLine,
} from "@karrotmarket/react-monochrome-icon";
import { ActionButton } from "seed-design/ui/action-button";
import { MenuContent, MenuGroup, MenuItem, MenuRoot, MenuTrigger } from "seed-design/ui/menu";
export default function MenuDisabled() {
return (
열기
} />
}
disabled
/>
} />
);
}
```
### Placement
`MenuRoot`의 `placement` prop으로 메뉴의 위치를 설정합니다. 기본값은 `"bottom"`입니다.
```tsx
import { IconPencilLine, IconPlusLine } from "@karrotmarket/react-monochrome-icon";
import { Box } from "@seed-design/react";
import { ActionButton } from "seed-design/ui/action-button";
import {
MenuContent,
MenuGroup,
MenuItem,
MenuRoot,
MenuTrigger,
type MenuRootProps,
} from "seed-design/ui/menu";
function PlacementMenu({ placement }: { placement: NonNullable }) {
return (
{placement}
} />
} />
);
}
export default function MenuPlacement() {
return (
);
}
```
### Anchor
`MenuAnchor`의 `children`은 Menu가 위치를 잡는 데에만 사용되며, `MenuTrigger`와 달리 클릭으로 열고 닫는 동작이 포함되지 않습니다.
`open` prop을 controlled하게 사용하여 열리고 닫힌 상태를 직접 관리해야 합니다.
아래 예시의 경우 `onOpenChange` 콜백에 조건을 추가하여 바깥 영역을 클릭한 경우에도 메뉴가 닫히지 않도록 구현되어 있습니다.
```tsx
import { Avatar } from "seed-design/ui/avatar";
import { IdentityPlaceholder } from "seed-design/ui/identity-placeholder";
import { IconPencilLine, IconPlusLine } from "@karrotmarket/react-monochrome-icon";
import { useState } from "react";
import { Switch } from "seed-design/ui/switch";
import { MenuAnchor, MenuContent, MenuGroup, MenuItem, MenuRoot } from "seed-design/ui/menu";
import { HStack } from "@seed-design/react";
export default function MenuAnchorExample() {
const [open, setOpen] = useState(false);
return (
{
if (!nextOpen && details?.reason === "interactOutside") return;
setOpen(nextOpen);
}}
>
}
/>
} />
} />
);
}
```
### Match Width
`MenuRoot`의 `matchReferenceWidth` prop을 사용하면 메뉴의 너비가 reference 요소(Trigger 또는 Anchor)의 너비에 맞춰집니다.
```tsx
import { ActionButton } from "seed-design/ui/action-button";
import { MenuContent, MenuGroup, MenuItem, MenuRoot, MenuTrigger } from "seed-design/ui/menu";
export default function MenuMatchReferenceWidth() {
return (
열기
);
}
```
### `onOpenChange` Details
`onOpenChange` 두 번째 인자로 `details`가 제공됩니다.
#### `reason`
**열릴 때** (`open: true`)
- `"trigger"`: `MenuTrigger`로 열림
**닫힐 때** (`open: false`)
- `"trigger"`: `MenuTrigger`로 닫힘
- `"escapeKeyDown"`: ESC 키 사용
- `"interactOutside"`: 외부 영역 클릭
- `"itemClick"`: 메뉴 항목 클릭
- `"cascadeDismiss"`: 상위 레이어 닫힘으로 인한 연쇄 닫힘
```tsx
import { IconPencilLine, IconPlusLine } from "@karrotmarket/react-monochrome-icon";
import { HStack, Text, VStack } from "@seed-design/react";
import { useState } from "react";
import { ActionButton } from "seed-design/ui/action-button";
import { MenuContent, MenuGroup, MenuItem, MenuRoot, MenuTrigger } from "seed-design/ui/menu";
export default function MenuOpenChangeReason() {
const [open, setOpen] = useState(false);
const [openReason, setOpenReason] = useState(null);
const [closeReason, setCloseReason] = useState(null);
return (
{
setOpen(open);
(open ? setOpenReason : setCloseReason)(details?.reason ?? null);
}}
>
열기
} />
} />
마지막 열림 이유: {openReason ?? "-"}
마지막 닫힘 이유: {closeReason ?? "-"}
);
}
```