@ceed/ads 1.35.1 → 1.37.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +85 -95
  2. package/dist/components/Accordions/Accordions.d.ts +1 -0
  3. package/dist/components/Alert/Alert.d.ts +5 -5
  4. package/dist/components/Autocomplete/Autocomplete.d.ts +2 -2
  5. package/dist/components/Avatar/Avatar.d.ts +7 -17
  6. package/dist/components/Box/Box.d.ts +1 -0
  7. package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +6 -5
  8. package/dist/components/Button/Button.d.ts +3 -2
  9. package/dist/components/Calendar/Calendar.d.ts +1 -0
  10. package/dist/components/Card/Card.d.ts +1 -0
  11. package/dist/components/Checkbox/Checkbox.d.ts +1 -0
  12. package/dist/components/Chip/Chip.d.ts +1 -0
  13. package/dist/components/Container/Container.d.ts +6 -1
  14. package/dist/components/DialogActions/DialogActions.d.ts +1 -0
  15. package/dist/components/DialogContent/DialogContent.d.ts +1 -0
  16. package/dist/components/DialogFrame/DialogFrame.d.ts +1 -1
  17. package/dist/components/DialogTitle/DialogTitle.d.ts +1 -0
  18. package/dist/components/Divider/Divider.d.ts +1 -0
  19. package/dist/components/Dropdown/Dropdown.d.ts +28 -1
  20. package/dist/components/FilterMenu/components/MonthRange.d.ts +11 -0
  21. package/dist/components/FilterMenu/types.d.ts +5 -1
  22. package/dist/components/FilterableCheckboxGroup/FilterableCheckboxGroup.d.ts +1 -1
  23. package/dist/components/FormControl/FormControl.d.ts +1 -0
  24. package/dist/components/FormHelperText/FormHelperText.d.ts +1 -0
  25. package/dist/components/FormLabel/FormLabel.d.ts +1 -0
  26. package/dist/components/Grid/Grid.d.ts +1 -0
  27. package/dist/components/IconButton/IconButton.d.ts +3 -2
  28. package/dist/components/IconMenuButton/IconMenuButton.d.ts +7 -6
  29. package/dist/components/InfoSign/InfoSign.d.ts +3 -2
  30. package/dist/components/Input/Input.d.ts +8 -22
  31. package/dist/components/InsetDrawer/InsetDrawer.d.ts +1 -0
  32. package/dist/components/Markdown/Markdown.d.ts +9 -24
  33. package/dist/components/Menu/Menu.d.ts +2 -1
  34. package/dist/components/MenuButton/MenuButton.d.ts +10 -8
  35. package/dist/components/Modal/Modal.d.ts +4 -2
  36. package/dist/components/NavigationGroup/NavigationGroup.d.ts +3 -2
  37. package/dist/components/NavigationItem/NavigationItem.d.ts +3 -2
  38. package/dist/components/Navigator/Navigator.d.ts +5 -4
  39. package/dist/components/Pagination/Pagination.d.ts +2 -2
  40. package/dist/components/ProfileMenu/ProfileMenu.d.ts +3 -3
  41. package/dist/components/Radio/Radio.d.ts +1 -0
  42. package/dist/components/RadioList/RadioList.d.ts +3 -2
  43. package/dist/components/Select/Select.d.ts +12 -10
  44. package/dist/components/Sheet/Sheet.d.ts +1 -0
  45. package/dist/components/Stack/Stack.d.ts +1 -0
  46. package/dist/components/Stepper/Stepper.d.ts +2 -1
  47. package/dist/components/Switch/Switch.d.ts +1 -0
  48. package/dist/components/Table/Table.d.ts +7 -5
  49. package/dist/components/Tabs/Tabs.d.ts +1 -0
  50. package/dist/components/Textarea/Textarea.d.ts +8 -20
  51. package/dist/components/ThemeProvider/ThemeProvider.d.ts +24 -2
  52. package/dist/components/Tooltip/Tooltip.d.ts +1 -0
  53. package/dist/components/Typography/Typography.d.ts +1 -0
  54. package/dist/components/Uploader/Uploader.d.ts +18 -17
  55. package/dist/components/data-display/Avatar.md +61 -73
  56. package/dist/components/data-display/Badge.md +198 -182
  57. package/dist/components/data-display/Chip.md +165 -143
  58. package/dist/components/data-display/DataTable.md +843 -338
  59. package/dist/components/data-display/InfoSign.md +1 -3
  60. package/dist/components/data-display/Markdown.md +93 -125
  61. package/dist/components/data-display/Table.md +1454 -1008
  62. package/dist/components/data-display/Tooltip.md +1 -1
  63. package/dist/components/data-display/Typography.md +101 -104
  64. package/dist/components/feedback/Alert.md +81 -87
  65. package/dist/components/feedback/CircularProgress.md +34 -38
  66. package/dist/components/feedback/Dialog.md +25 -17
  67. package/dist/components/feedback/Modal.md +297 -266
  68. package/dist/components/feedback/Skeleton.md +125 -89
  69. package/dist/components/index.d.ts +60 -1
  70. package/dist/components/inputs/Autocomplete.md +192 -96
  71. package/dist/components/inputs/Button.md +85 -85
  72. package/dist/components/inputs/ButtonGroup.md +197 -187
  73. package/dist/components/inputs/Calendar.md +25 -28
  74. package/dist/components/inputs/Checkbox.md +13 -31
  75. package/dist/components/inputs/CurrencyInput.md +6 -6
  76. package/dist/components/inputs/DatePicker.md +229 -110
  77. package/dist/components/inputs/DateRangePicker.md +248 -137
  78. package/dist/components/inputs/FilterMenu.md +138 -8
  79. package/dist/components/inputs/FilterableCheckboxGroup.md +116 -56
  80. package/dist/components/inputs/FormControl.md +76 -70
  81. package/dist/components/inputs/IconButton.md +231 -207
  82. package/dist/components/inputs/Input.md +133 -100
  83. package/dist/components/inputs/MonthPicker.md +186 -84
  84. package/dist/components/inputs/MonthRangePicker.md +73 -49
  85. package/dist/components/inputs/PercentageInput.md +17 -33
  86. package/dist/components/inputs/RadioButton.md +322 -258
  87. package/dist/components/inputs/RadioList.md +68 -52
  88. package/dist/components/inputs/RadioTileGroup.md +287 -170
  89. package/dist/components/inputs/SearchBar.md +82 -60
  90. package/dist/components/inputs/Select.md +108 -97
  91. package/dist/components/inputs/Slider.md +155 -104
  92. package/dist/components/inputs/Switch.md +194 -139
  93. package/dist/components/inputs/Textarea.md +17 -22
  94. package/dist/components/inputs/Uploader/Uploader.md +69 -40
  95. package/dist/components/layout/Box.md +841 -662
  96. package/dist/components/layout/Container.md +3 -11
  97. package/dist/components/layout/Grid.md +480 -394
  98. package/dist/components/layout/Stack.md +739 -566
  99. package/dist/components/navigation/Breadcrumbs.md +182 -116
  100. package/dist/components/navigation/Dropdown.md +732 -391
  101. package/dist/components/navigation/IconMenuButton.md +15 -7
  102. package/dist/components/navigation/InsetDrawer.md +550 -378
  103. package/dist/components/navigation/Link.md +104 -94
  104. package/dist/components/navigation/Menu.md +624 -503
  105. package/dist/components/navigation/MenuButton.md +19 -11
  106. package/dist/components/navigation/NavigationGroup.md +19 -50
  107. package/dist/components/navigation/NavigationItem.md +6 -6
  108. package/dist/components/navigation/Navigator.md +26 -28
  109. package/dist/components/navigation/Pagination.md +87 -76
  110. package/dist/components/navigation/ProfileMenu.md +67 -45
  111. package/dist/components/navigation/Stepper.md +2 -12
  112. package/dist/components/navigation/Tabs.md +210 -184
  113. package/dist/components/surfaces/Accordions.md +90 -173
  114. package/dist/components/surfaces/Card.md +1096 -711
  115. package/dist/components/surfaces/Divider.md +562 -412
  116. package/dist/components/surfaces/Sheet.md +700 -518
  117. package/dist/guides/ThemeProvider.md +65 -40
  118. package/dist/index.browser.js +5 -5
  119. package/dist/index.browser.js.map +4 -4
  120. package/dist/index.cjs +1906 -1690
  121. package/dist/index.d.ts +1 -1
  122. package/dist/index.js +1404 -1180
  123. package/framer/index.js +1 -1
  124. package/package.json +34 -36
@@ -1,20 +1,20 @@
1
1
  # Dropdown
2
2
 
3
- Dropdown is the stateful container that orchestrates the open/close behavior of a menu system. It acts as the invisible glue between a trigger element (such as MenuButton or IconMenuButton) and the Menu that appears when activated. Dropdown itself renders no visible UI -- it provides context so that its children can coordinate with each other.
3
+ Dropdown is the stateful container that orchestrates the open/close behavior of a menu system. It acts as the invisible glue between a trigger element (`MenuButtonTrigger`) and the Menu that appears when activated. Dropdown itself renders no visible UI -- it provides context so that its children can coordinate with each other.
4
4
 
5
- Dropdown is part of a **composition pattern** together with Menu, MenuItem, MenuButton, and IconMenuButton. While MenuButton and IconMenuButton are higher-level convenience components that bundle trigger + menu into a single prop-driven API, Dropdown gives you full control over the trigger element, menu content, and layout when you need custom compositions.
5
+ Dropdown is part of a **composition pattern** together with `MenuButtonTrigger`, `Menu`, and `MenuItem`. `MenuButtonTrigger` is the low-level trigger that connects to the Dropdown context; the standalone `MenuButton` and `IconMenuButton` are higher-level convenience components that bundle trigger + menu into a single prop-driven API. Use the Dropdown composition when you need full control over the trigger element, menu content, and layout. All of these symbols are imported from `@ceed/ads`.
6
6
 
7
7
  ```tsx
8
8
  <Dropdown>
9
- <MenuButton variant="outlined" endDecorator={<ExpandMoreIcon />}>
10
- 메뉴 열기
11
- </MenuButton>
12
- <Menu>
13
- <MenuItem>옵션 1</MenuItem>
14
- <MenuItem>옵션 2</MenuItem>
15
- <MenuItem>옵션 3</MenuItem>
16
- </Menu>
17
- </Dropdown>
9
+ <MenuButtonTrigger variant="outlined" endDecorator={<ExpandMoreIcon />}>
10
+ 메뉴 열기
11
+ </MenuButtonTrigger>
12
+ <Menu>
13
+ <MenuItem>옵션 1</MenuItem>
14
+ <MenuItem>옵션 2</MenuItem>
15
+ <MenuItem>옵션 3</MenuItem>
16
+ </Menu>
17
+ </Dropdown>
18
18
  ```
19
19
 
20
20
  | Field | Description | Default |
@@ -24,13 +24,12 @@ Dropdown is part of a **composition pattern** together with Menu, MenuItem, Menu
24
24
  ## Usage
25
25
 
26
26
  ```tsx
27
- import { Dropdown, Menu, MenuItem } from '@ceed/ads';
28
- import { MenuButton } from '@ceed/ads';
27
+ import { Dropdown, MenuButtonTrigger, Menu, MenuItem } from '@ceed/ads';
29
28
 
30
29
  function MyComponent() {
31
30
  return (
32
31
  <Dropdown>
33
- <MenuButton>Open Menu</MenuButton>
32
+ <MenuButtonTrigger>Open Menu</MenuButtonTrigger>
34
33
  <Menu>
35
34
  <MenuItem>Option 1</MenuItem>
36
35
  <MenuItem>Option 2</MenuItem>
@@ -41,83 +40,338 @@ function MyComponent() {
41
40
  }
42
41
  ```
43
42
 
43
+ > **`MenuButtonTrigger` vs `MenuButton`**: `MenuButtonTrigger` is the low-level trigger for the Dropdown composition (Joy UI's `MenuButton`, re-exported from `@ceed/ads` under this name). The separate `MenuButton` exported from `@ceed/ads` is a higher-level, self-contained component (driven by `buttonText` / `items` props) that renders its **own** Dropdown internally — it cannot be nested inside `<Dropdown>`.
44
+
44
45
  ## Composition Pattern
45
46
 
46
47
  Dropdown, Menu, MenuItem, MenuButton, and IconMenuButton form a **menu component family**. Choose the right level of abstraction for your use case:
47
48
 
48
- | Approach | When to use |
49
- | ------------------------------------ | ------------------------------------------------------- |
50
- | `MenuButton` (standalone) | Simple text-triggered menus with a list of items |
51
- | `IconMenuButton` (standalone) | Icon-only triggers in space-constrained areas |
52
- | `Dropdown` + `MenuButton` + `Menu` | Custom menu content (headers, dividers, mixed elements) |
53
- | `Dropdown` + custom trigger + `Menu` | Fully custom trigger elements |
49
+ | Approach | When to use |
50
+ | ----------------------------------------- | ------------------------------------------------------- |
51
+ | `MenuButton` (standalone) | Simple text-triggered menus with a list of items |
52
+ | `IconMenuButton` (standalone) | Icon-only triggers in space-constrained areas |
53
+ | `Dropdown` + `MenuButtonTrigger` + `Menu` | Custom menu content (headers, dividers, mixed elements) |
54
+ | `Dropdown` + custom trigger + `Menu` | Fully custom trigger elements |
54
55
 
55
- ## Dropdown Basic
56
+ ## Custom Trigger Components
56
57
 
57
- The simplest Dropdown pairs a MenuButton trigger with a Menu of items.
58
+ The Dropdown trigger is **not limited to a plain button**. `MenuButtonTrigger` is simply the element that wires the open/close behavior — `onClick`, `aria-haspopup`, `aria-expanded`, focus management, and a `ref` into the Dropdown context. You can render that behavior into a different component in two ways:
59
+
60
+ - **`slots={{ root: YourComponent }}`** — replace the trigger entirely with another component (e.g. `Button`, `IconButton`). `MenuButtonTrigger` injects all of the trigger behavior into your component as the root slot. Pass props to it via `slotProps={{ root: { ... } }}`.
61
+ - **`slotProps={{ root: { component: 'a' } }}`** (or the `component` prop) — keep `MenuButtonTrigger`'s styling and behavior but render a different HTML element.
62
+
63
+ This is exactly how the higher-level `IconMenuButton` is built internally (`slots={{ root: IconButton }}`). The only requirement is that the chosen root is focusable and clickable — prefer button-like components (`Button`, `IconButton`). For non-interactive components like `Avatar`, wrap them in a button-like root rather than using them directly.
58
64
 
59
65
  ```tsx
60
- <Stack direction="row" spacing={2}>
61
- <Dropdown>
62
- <MenuButton>기본 메뉴</MenuButton>
66
+ import { Dropdown, MenuButtonTrigger, Menu, MenuItem, Button } from '@ceed/ads';
67
+
68
+ // Any button-like component as the trigger
69
+ <Dropdown>
70
+ <MenuButtonTrigger slots={{ root: Button }} slotProps={{ root: { variant: 'soft', color: 'primary' } }}>
71
+ Open
72
+ </MenuButtonTrigger>
73
+ <Menu>
74
+ <MenuItem>Option 1</MenuItem>
75
+ <MenuItem>Option 2</MenuItem>
76
+ </Menu>
77
+ </Dropdown>;
78
+ ```
79
+
80
+ > **Note**: Every component above — including `MenuButtonTrigger` — is imported from `@ceed/ads`. No direct `@mui/joy` import is required.
81
+
82
+ ## Button as Dropdown Trigger
83
+
84
+ Replace the trigger with the HDS `Button` via `slots={{ root: Button }}` to match your button styling system.
85
+
86
+ ```tsx
87
+ <Dropdown>
88
+ <MenuButtonTrigger
89
+ slots={{
90
+ root: Button
91
+ }}
92
+ slotProps={{
93
+ root: {
94
+ variant: "soft",
95
+ color: "primary",
96
+ endDecorator: <KeyboardArrowDownIcon />
97
+ }
98
+ }}
99
+ >
100
+ HDS Button 트리거
101
+ </MenuButtonTrigger>
63
102
  <Menu>
64
- <MenuItem>첫 번째 옵션</MenuItem>
65
- <MenuItem>두 번째 옵션</MenuItem>
66
- <MenuItem>세 번째 옵션</MenuItem>
103
+ <MenuItem>옵션 1</MenuItem>
104
+ <MenuItem>옵션 2</MenuItem>
105
+ <MenuItem>옵션 3</MenuItem>
67
106
  </Menu>
68
107
  </Dropdown>
108
+ ```
69
109
 
70
- <Dropdown>
71
- <MenuButton variant="outlined" endDecorator={<ExpandMoreIcon />}>
72
- 아이콘 포함
73
- </MenuButton>
74
- <Menu>
75
- <MenuItem>옵션 A</MenuItem>
76
- <MenuItem>옵션 B</MenuItem>
77
- <MenuItem>옵션 C</MenuItem>
110
+ ## IconButton Trigger
111
+
112
+ For space-constrained areas like table rows or card headers, use an `IconButton` as the trigger. Always provide an `aria-label`.
113
+
114
+ ```tsx
115
+ <Dropdown>
116
+ <MenuButtonTrigger
117
+ slots={{
118
+ root: IconButton
119
+ }}
120
+ slotProps={{
121
+ root: {
122
+ variant: "plain",
123
+ color: "neutral",
124
+ "aria-label": "추가 작업"
125
+ }
126
+ }}
127
+ >
128
+ <MoreVertIcon />
129
+ </MenuButtonTrigger>
130
+ <Menu placement="bottom-end">
131
+ <MenuItem>
132
+ <EditIcon
133
+ sx={{
134
+ mr: 1
135
+ }}
136
+ />
137
+ 편집
138
+ </MenuItem>
139
+ <MenuItem>
140
+ <DeleteIcon
141
+ sx={{
142
+ mr: 1,
143
+ color: "danger.500"
144
+ }}
145
+ />
146
+ <Typography color="danger">삭제</Typography>
147
+ </MenuItem>
78
148
  </Menu>
79
149
  </Dropdown>
80
- </Stack>
81
150
  ```
82
151
 
83
- ## Dropdown Button Variants
152
+ ## Avatar Trigger
84
153
 
85
- MenuButton supports `plain`, `outlined`, `soft`, and `solid` variants to match your design context.
154
+ Profile menus often use an avatar as the trigger. Wrap the `Avatar` in a button-like `IconButton` root so the trigger stays keyboard- and screen-reader-accessible.
86
155
 
87
156
  ```tsx
88
- <Stack direction="row" spacing={2} flexWrap="wrap">
89
- <Dropdown>
90
- <MenuButton variant="plain">Plain</MenuButton>
91
- <Menu>
92
- <MenuItem>옵션 1</MenuItem>
93
- <MenuItem>옵션 2</MenuItem>
157
+ <Dropdown>
158
+ <MenuButtonTrigger
159
+ slots={{
160
+ root: IconButton
161
+ }}
162
+ slotProps={{
163
+ root: {
164
+ variant: "plain",
165
+ color: "neutral",
166
+ "aria-label": "프로필 메뉴",
167
+ sx: {
168
+ borderRadius: "50%",
169
+ p: 0
170
+ }
171
+ }
172
+ }}
173
+ >
174
+ <Avatar size="sm" variant="soft" color="primary">
175
+
176
+ </Avatar>
177
+ </MenuButtonTrigger>
178
+ <Menu
179
+ placement="bottom-end"
180
+ sx={{
181
+ minWidth: 180
182
+ }}
183
+ >
184
+ <Stack px={2} py={1} spacing={0.5}>
185
+ <Typography level="title-sm" fontWeight="bold">
186
+ 김철수
187
+ </Typography>
188
+ <Typography level="body-xs" color="neutral">
189
+ kim@example.com
190
+ </Typography>
191
+ </Stack>
192
+ <ListDivider />
193
+ <MenuItem>
194
+ <PersonIcon
195
+ sx={{
196
+ mr: 1
197
+ }}
198
+ />
199
+ 내 프로필
200
+ </MenuItem>
201
+ <MenuItem>
202
+ <LogoutIcon
203
+ sx={{
204
+ mr: 1
205
+ }}
206
+ />
207
+ 로그아웃
208
+ </MenuItem>
94
209
  </Menu>
95
210
  </Dropdown>
211
+ ```
96
212
 
97
- <Dropdown>
98
- <MenuButton variant="outlined">Outlined</MenuButton>
213
+ ## Custom Trigger Element
214
+
215
+ To keep `MenuButtonTrigger`'s behavior and styling but render a different HTML tag, set `slotProps={{ root: { component: 'a' } }}`.
216
+
217
+ ```tsx
218
+ <Dropdown>
219
+ <MenuButtonTrigger
220
+ variant="outlined"
221
+ slotProps={{
222
+ root: {
223
+ component: "a",
224
+ role: "button"
225
+ }
226
+ }}
227
+ endDecorator={<ExpandMoreIcon />}
228
+ sx={{
229
+ cursor: "pointer"
230
+ }}
231
+ >
232
+ 앵커(a) 엘리먼트 트리거
233
+ </MenuButtonTrigger>
99
234
  <Menu>
100
235
  <MenuItem>옵션 1</MenuItem>
101
236
  <MenuItem>옵션 2</MenuItem>
102
237
  </Menu>
103
238
  </Dropdown>
239
+ ```
104
240
 
105
- <Dropdown>
106
- <MenuButton variant="soft">Soft</MenuButton>
241
+ ## useMenuButton Hook Trigger
242
+
243
+ When you want a fully custom trigger element without using `MenuButtonTrigger` at all, use the `useMenuButton` hook. Call it inside a child of `<Dropdown>` and spread `getRootProps()` onto any element — the hook wires `onClick`, `aria-*`, and the `ref` into the Dropdown context. Render a native `<button>` (or add keyboard handling) so the trigger stays accessible.
244
+
245
+ ```tsx
246
+ import { Dropdown, useMenuButton, Menu, MenuItem, Box } from '@ceed/ads';
247
+
248
+ function HookTrigger({ children }) {
249
+ const { getRootProps, open } = useMenuButton();
250
+ return (
251
+ <Box component="button" {...getRootProps()} sx={{ cursor: 'pointer' /* custom styles */ }}>
252
+ {children}
253
+ </Box>
254
+ );
255
+ }
256
+
257
+ <Dropdown>
258
+ <HookTrigger>Custom trigger</HookTrigger>
259
+ <Menu>
260
+ <MenuItem>Option 1</MenuItem>
261
+ <MenuItem>Option 2</MenuItem>
262
+ </Menu>
263
+ </Dropdown>;
264
+ ```
265
+
266
+ ```tsx
267
+ <Dropdown>
268
+ <HookTrigger>완전 커스텀 트리거 (useMenuButton)</HookTrigger>
107
269
  <Menu>
108
270
  <MenuItem>옵션 1</MenuItem>
109
271
  <MenuItem>옵션 2</MenuItem>
272
+ <MenuItem>옵션 3</MenuItem>
110
273
  </Menu>
111
274
  </Dropdown>
275
+ ```
112
276
 
113
- <Dropdown>
114
- <MenuButton variant="solid">Solid</MenuButton>
277
+ > **Note**: A trigger is always required — Dropdown itself renders no UI and only provides open/close state plus the anchor context. The trigger can be `MenuButtonTrigger` (optionally with `slots` / `component`) or your own element wired via `useMenuButton`. Both read the same Dropdown context, and both are available from `@ceed/ads`.
278
+
279
+ ## useMenuButton with Button
280
+
281
+ You can also spread `getRootProps()` onto the HDS `Button`. Because `Button` renders a native `<button>`, it already provides focusability, Enter/Space activation, and the `button` role — so accessibility is preserved by adding only the `aria-*` / `onClick` / `ref` from the hook. `getRootProps()` does not include `onKeyDown`, which is why a native button (not a `div`) matters here.
282
+
283
+ ```tsx
284
+ import { Dropdown, useMenuButton, Menu, MenuItem, Button } from '@ceed/ads';
285
+
286
+ function HookButton({ children }) {
287
+ const { getRootProps, open } = useMenuButton();
288
+ return (
289
+ <Button {...getRootProps()} variant={open ? 'soft' : 'outlined'} color="neutral">
290
+ {children}
291
+ </Button>
292
+ );
293
+ }
294
+ ```
295
+
296
+ ```tsx
297
+ <Dropdown>
298
+ <HookButton>useMenuButton + Button</HookButton>
115
299
  <Menu>
116
300
  <MenuItem>옵션 1</MenuItem>
117
301
  <MenuItem>옵션 2</MenuItem>
302
+ <MenuItem>옵션 3</MenuItem>
118
303
  </Menu>
119
304
  </Dropdown>
120
- </Stack>
305
+ ```
306
+
307
+ > **Tip**: For a plain button trigger, prefer `MenuButtonTrigger slots={{ root: Button }}` — it is more concise and wires the menu keyboard behavior for you. Reach for `useMenuButton` when you need a non-button or deeply custom trigger element.
308
+
309
+ ## Dropdown Basic
310
+
311
+ The simplest Dropdown pairs a `MenuButtonTrigger` with a Menu of items.
312
+
313
+ ```tsx
314
+ <Stack direction="row" spacing={2}>
315
+ <Dropdown>
316
+ <MenuButtonTrigger>기본 메뉴</MenuButtonTrigger>
317
+ <Menu>
318
+ <MenuItem>첫 번째 옵션</MenuItem>
319
+ <MenuItem>두 번째 옵션</MenuItem>
320
+ <MenuItem>세 번째 옵션</MenuItem>
321
+ </Menu>
322
+ </Dropdown>
323
+
324
+ <Dropdown>
325
+ <MenuButtonTrigger variant="outlined" endDecorator={<ExpandMoreIcon />}>
326
+ 아이콘 포함
327
+ </MenuButtonTrigger>
328
+ <Menu>
329
+ <MenuItem>옵션 A</MenuItem>
330
+ <MenuItem>옵션 B</MenuItem>
331
+ <MenuItem>옵션 C</MenuItem>
332
+ </Menu>
333
+ </Dropdown>
334
+ </Stack>
335
+ ```
336
+
337
+ ## Dropdown Button Variants
338
+
339
+ `MenuButtonTrigger` supports `plain`, `outlined`, `soft`, and `solid` variants to match your design context.
340
+
341
+ ```tsx
342
+ <Stack direction="row" spacing={2} flexWrap="wrap">
343
+ <Dropdown>
344
+ <MenuButtonTrigger variant="plain">Plain</MenuButtonTrigger>
345
+ <Menu>
346
+ <MenuItem>옵션 1</MenuItem>
347
+ <MenuItem>옵션 2</MenuItem>
348
+ </Menu>
349
+ </Dropdown>
350
+
351
+ <Dropdown>
352
+ <MenuButtonTrigger variant="outlined">Outlined</MenuButtonTrigger>
353
+ <Menu>
354
+ <MenuItem>옵션 1</MenuItem>
355
+ <MenuItem>옵션 2</MenuItem>
356
+ </Menu>
357
+ </Dropdown>
358
+
359
+ <Dropdown>
360
+ <MenuButtonTrigger variant="soft">Soft</MenuButtonTrigger>
361
+ <Menu>
362
+ <MenuItem>옵션 1</MenuItem>
363
+ <MenuItem>옵션 2</MenuItem>
364
+ </Menu>
365
+ </Dropdown>
366
+
367
+ <Dropdown>
368
+ <MenuButtonTrigger variant="solid">Solid</MenuButtonTrigger>
369
+ <Menu>
370
+ <MenuItem>옵션 1</MenuItem>
371
+ <MenuItem>옵션 2</MenuItem>
372
+ </Menu>
373
+ </Dropdown>
374
+ </Stack>
121
375
  ```
122
376
 
123
377
  ## Dropdown Button Colors
@@ -126,56 +380,56 @@ Apply semantic colors to the trigger button for different emphasis levels.
126
380
 
127
381
  ```tsx
128
382
  <Stack direction="row" spacing={2} flexWrap="wrap">
129
- <Dropdown>
130
- <MenuButton color="primary" variant="soft">
131
- Primary
132
- </MenuButton>
133
- <Menu>
134
- <MenuItem>옵션 1</MenuItem>
135
- <MenuItem>옵션 2</MenuItem>
136
- </Menu>
137
- </Dropdown>
383
+ <Dropdown>
384
+ <MenuButtonTrigger color="primary" variant="soft">
385
+ Primary
386
+ </MenuButtonTrigger>
387
+ <Menu>
388
+ <MenuItem>옵션 1</MenuItem>
389
+ <MenuItem>옵션 2</MenuItem>
390
+ </Menu>
391
+ </Dropdown>
138
392
 
139
- <Dropdown>
140
- <MenuButton color="neutral" variant="soft">
141
- Neutral
142
- </MenuButton>
143
- <Menu>
144
- <MenuItem>옵션 1</MenuItem>
145
- <MenuItem>옵션 2</MenuItem>
146
- </Menu>
147
- </Dropdown>
393
+ <Dropdown>
394
+ <MenuButtonTrigger color="neutral" variant="soft">
395
+ Neutral
396
+ </MenuButtonTrigger>
397
+ <Menu>
398
+ <MenuItem>옵션 1</MenuItem>
399
+ <MenuItem>옵션 2</MenuItem>
400
+ </Menu>
401
+ </Dropdown>
148
402
 
149
- <Dropdown>
150
- <MenuButton color="danger" variant="soft">
151
- Danger
152
- </MenuButton>
153
- <Menu>
154
- <MenuItem>옵션 1</MenuItem>
155
- <MenuItem>옵션 2</MenuItem>
156
- </Menu>
157
- </Dropdown>
403
+ <Dropdown>
404
+ <MenuButtonTrigger color="danger" variant="soft">
405
+ Danger
406
+ </MenuButtonTrigger>
407
+ <Menu>
408
+ <MenuItem>옵션 1</MenuItem>
409
+ <MenuItem>옵션 2</MenuItem>
410
+ </Menu>
411
+ </Dropdown>
158
412
 
159
- <Dropdown>
160
- <MenuButton color="success" variant="soft">
161
- Success
162
- </MenuButton>
163
- <Menu>
164
- <MenuItem>옵션 1</MenuItem>
165
- <MenuItem>옵션 2</MenuItem>
166
- </Menu>
167
- </Dropdown>
413
+ <Dropdown>
414
+ <MenuButtonTrigger color="success" variant="soft">
415
+ Success
416
+ </MenuButtonTrigger>
417
+ <Menu>
418
+ <MenuItem>옵션 1</MenuItem>
419
+ <MenuItem>옵션 2</MenuItem>
420
+ </Menu>
421
+ </Dropdown>
168
422
 
169
- <Dropdown>
170
- <MenuButton color="warning" variant="soft">
171
- Warning
172
- </MenuButton>
173
- <Menu>
174
- <MenuItem>옵션 1</MenuItem>
175
- <MenuItem>옵션 2</MenuItem>
176
- </Menu>
177
- </Dropdown>
178
- </Stack>
423
+ <Dropdown>
424
+ <MenuButtonTrigger color="warning" variant="soft">
425
+ Warning
426
+ </MenuButtonTrigger>
427
+ <Menu>
428
+ <MenuItem>옵션 1</MenuItem>
429
+ <MenuItem>옵션 2</MenuItem>
430
+ </Menu>
431
+ </Dropdown>
432
+ </Stack>
179
433
  ```
180
434
 
181
435
  ## Dropdown Menu Placements
@@ -183,45 +437,49 @@ Apply semantic colors to the trigger button for different emphasis levels.
183
437
  Control where the menu appears relative to the trigger using the `placement` prop on Menu.
184
438
 
185
439
  ```tsx
186
- <Stack direction="row" spacing={2} sx={{
187
- mt: 4
188
- }}>
189
- <Dropdown>
190
- <MenuButton variant="outlined">Bottom Start</MenuButton>
191
- <Menu placement="bottom-start">
192
- <MenuItem>옵션 1</MenuItem>
193
- <MenuItem>옵션 2</MenuItem>
194
- <MenuItem>옵션 3</MenuItem>
195
- </Menu>
196
- </Dropdown>
440
+ <Stack
441
+ direction="row"
442
+ spacing={2}
443
+ sx={{
444
+ mt: 4
445
+ }}
446
+ >
447
+ <Dropdown>
448
+ <MenuButtonTrigger variant="outlined">Bottom Start</MenuButtonTrigger>
449
+ <Menu placement="bottom-start">
450
+ <MenuItem>옵션 1</MenuItem>
451
+ <MenuItem>옵션 2</MenuItem>
452
+ <MenuItem>옵션 3</MenuItem>
453
+ </Menu>
454
+ </Dropdown>
197
455
 
198
- <Dropdown>
199
- <MenuButton variant="outlined">Bottom</MenuButton>
200
- <Menu placement="bottom">
201
- <MenuItem>옵션 1</MenuItem>
202
- <MenuItem>옵션 2</MenuItem>
203
- <MenuItem>옵션 3</MenuItem>
204
- </Menu>
205
- </Dropdown>
456
+ <Dropdown>
457
+ <MenuButtonTrigger variant="outlined">Bottom</MenuButtonTrigger>
458
+ <Menu placement="bottom">
459
+ <MenuItem>옵션 1</MenuItem>
460
+ <MenuItem>옵션 2</MenuItem>
461
+ <MenuItem>옵션 3</MenuItem>
462
+ </Menu>
463
+ </Dropdown>
206
464
 
207
- <Dropdown>
208
- <MenuButton variant="outlined">Bottom End</MenuButton>
209
- <Menu placement="bottom-end">
210
- <MenuItem>옵션 1</MenuItem>
211
- <MenuItem>옵션 2</MenuItem>
212
- <MenuItem>옵션 3</MenuItem>
213
- </Menu>
214
- </Dropdown>
465
+ <Dropdown>
466
+ <MenuButtonTrigger variant="outlined">Bottom End</MenuButtonTrigger>
467
+ <Menu placement="bottom-end">
468
+ <MenuItem>옵션 1</MenuItem>
469
+ <MenuItem>옵션 2</MenuItem>
470
+ <MenuItem>옵션 3</MenuItem>
471
+ </Menu>
472
+ </Dropdown>
215
473
 
216
- <Dropdown>
217
- <MenuButton variant="outlined">Top Start</MenuButton>
218
- <Menu placement="top-start">
219
- <MenuItem>옵션 1</MenuItem>
220
- <MenuItem>옵션 2</MenuItem>
221
- <MenuItem>옵션 3</MenuItem>
222
- </Menu>
223
- </Dropdown>
224
- </Stack>
474
+ <Dropdown>
475
+ <MenuButtonTrigger variant="outlined">Top Start</MenuButtonTrigger>
476
+ <Menu placement="top-start">
477
+ <MenuItem>옵션 1</MenuItem>
478
+ <MenuItem>옵션 2</MenuItem>
479
+ <MenuItem>옵션 3</MenuItem>
480
+ </Menu>
481
+ </Dropdown>
482
+ </Stack>
225
483
  ```
226
484
 
227
485
  ## Dropdown with Icons
@@ -230,31 +488,41 @@ Add icons to menu items and decorators to the trigger button for richer visual c
230
488
 
231
489
  ```tsx
232
490
  <Dropdown>
233
- <MenuButton variant="outlined" startDecorator={<PersonIcon />} endDecorator={<ExpandMoreIcon />}>
234
- 사용자 메뉴
235
- </MenuButton>
236
- <Menu>
237
- <MenuItem>
238
- <PersonIcon sx={{
239
- mr: 1
240
- }} />
241
- 프로필 보기
242
- </MenuItem>
243
- <MenuItem>
244
- <SettingsIcon sx={{
245
- mr: 1
246
- }} />
247
- 설정
248
- </MenuItem>
249
- <ListDivider />
250
- <MenuItem>
251
- <LogoutIcon sx={{
252
- mr: 1
253
- }} />
254
- 로그아웃
255
- </MenuItem>
256
- </Menu>
257
- </Dropdown>
491
+ <MenuButtonTrigger
492
+ variant="outlined"
493
+ startDecorator={<PersonIcon />}
494
+ endDecorator={<ExpandMoreIcon />}
495
+ >
496
+ 사용자 메뉴
497
+ </MenuButtonTrigger>
498
+ <Menu>
499
+ <MenuItem>
500
+ <PersonIcon
501
+ sx={{
502
+ mr: 1
503
+ }}
504
+ />
505
+ 프로필 보기
506
+ </MenuItem>
507
+ <MenuItem>
508
+ <SettingsIcon
509
+ sx={{
510
+ mr: 1
511
+ }}
512
+ />
513
+ 설정
514
+ </MenuItem>
515
+ <ListDivider />
516
+ <MenuItem>
517
+ <LogoutIcon
518
+ sx={{
519
+ mr: 1
520
+ }}
521
+ />
522
+ 로그아웃
523
+ </MenuItem>
524
+ </Menu>
525
+ </Dropdown>
258
526
  ```
259
527
 
260
528
  ## Dropdown Actions Menu
@@ -263,29 +531,38 @@ Build action menus for edit, delete, and other operations. Use `color="danger"`
263
531
 
264
532
  ```tsx
265
533
  <Dropdown>
266
- <MenuButton variant="plain" color="neutral" endDecorator={<ExpandMoreIcon />} sx={{
267
- fontSize: 'sm'
268
- }}>
269
- 작업
270
- </MenuButton>
271
- <Menu>
272
- <MenuItem>
273
- <EditIcon sx={{
274
- mr: 1,
275
- fontSize: 'sm'
276
- }} />
277
- 편집
278
- </MenuItem>
279
- <MenuItem>
280
- <DeleteIcon sx={{
281
- mr: 1,
282
- fontSize: 'sm',
283
- color: 'danger.500'
284
- }} />
285
- <Typography color="danger">삭제</Typography>
286
- </MenuItem>
287
- </Menu>
288
- </Dropdown>
534
+ <MenuButtonTrigger
535
+ variant="plain"
536
+ color="neutral"
537
+ endDecorator={<ExpandMoreIcon />}
538
+ sx={{
539
+ fontSize: "sm"
540
+ }}
541
+ >
542
+ 작업
543
+ </MenuButtonTrigger>
544
+ <Menu>
545
+ <MenuItem>
546
+ <EditIcon
547
+ sx={{
548
+ mr: 1,
549
+ fontSize: "sm"
550
+ }}
551
+ />
552
+ 편집
553
+ </MenuItem>
554
+ <MenuItem>
555
+ <DeleteIcon
556
+ sx={{
557
+ mr: 1,
558
+ fontSize: "sm",
559
+ color: "danger.500"
560
+ }}
561
+ />
562
+ <Typography color="danger">삭제</Typography>
563
+ </MenuItem>
564
+ </Menu>
565
+ </Dropdown>
289
566
  ```
290
567
 
291
568
  ## Dropdown Filter Menu
@@ -294,16 +571,20 @@ Use Dropdown as an interactive filter selector with state management.
294
571
 
295
572
  ```tsx
296
573
  <Dropdown>
297
- <MenuButton variant="outlined" startDecorator={<FilterListIcon />} endDecorator={<ExpandMoreIcon />}>
298
- 필터: {selectedFilter}
299
- </MenuButton>
300
- <Menu>
301
- <MenuItem onClick={() => setSelectedFilter('전체')}>전체</MenuItem>
302
- <MenuItem onClick={() => setSelectedFilter('활성')}>활성</MenuItem>
303
- <MenuItem onClick={() => setSelectedFilter('비활성')}>비활성</MenuItem>
304
- <MenuItem onClick={() => setSelectedFilter('대기중')}>대기중</MenuItem>
305
- </Menu>
306
- </Dropdown>
574
+ <MenuButtonTrigger
575
+ variant="outlined"
576
+ startDecorator={<FilterListIcon />}
577
+ endDecorator={<ExpandMoreIcon />}
578
+ >
579
+ 필터: {selectedFilter}
580
+ </MenuButtonTrigger>
581
+ <Menu>
582
+ <MenuItem onClick={() => setSelectedFilter("전체")}>전체</MenuItem>
583
+ <MenuItem onClick={() => setSelectedFilter("활성")}>활성</MenuItem>
584
+ <MenuItem onClick={() => setSelectedFilter("비활성")}>비활성</MenuItem>
585
+ <MenuItem onClick={() => setSelectedFilter("대기중")}>대기중</MenuItem>
586
+ </Menu>
587
+ </Dropdown>
307
588
  ```
308
589
 
309
590
  ## Dropdown Profile
@@ -312,50 +593,67 @@ Combine custom content (user info header) with standard menu items for profile m
312
593
 
313
594
  ```tsx
314
595
  <Dropdown>
315
- <MenuButton variant="plain" color="neutral" startDecorator={<Avatar size="sm" variant="soft" color="primary">
316
-
317
- </Avatar>} endDecorator={<ExpandMoreIcon />} sx={{
318
- gap: 1,
319
- padding: 1
320
- }}>
321
- 김철수
322
- </MenuButton>
323
- <Menu sx={{
324
- minWidth: 200
325
- }}>
326
- <Stack px={2} py={1.5} spacing={0.5}>
327
- <Typography level="title-sm" fontWeight="bold">
328
- 김철수
329
- </Typography>
330
- <Typography level="body-xs" color="neutral">
331
- kim@example.com
332
- </Typography>
333
- </Stack>
334
-
335
- <ListDivider />
336
-
337
- <MenuItem>
338
- <PersonIcon sx={{
339
- mr: 1
340
- }} />내 프로필
341
- </MenuItem>
342
- <MenuItem>
343
- <SettingsIcon sx={{
344
- mr: 1
345
- }} />
346
- 계정 설정
347
- </MenuItem>
348
-
349
- <ListDivider />
350
-
351
- <MenuItem>
352
- <LogoutIcon sx={{
353
- mr: 1
354
- }} />
355
- 로그아웃
356
- </MenuItem>
357
- </Menu>
358
- </Dropdown>
596
+ <MenuButtonTrigger
597
+ variant="plain"
598
+ color="neutral"
599
+ startDecorator={
600
+ <Avatar size="sm" variant="soft" color="primary">
601
+
602
+ </Avatar>
603
+ }
604
+ endDecorator={<ExpandMoreIcon />}
605
+ sx={{
606
+ gap: 1,
607
+ padding: 1
608
+ }}
609
+ >
610
+ 김철수
611
+ </MenuButtonTrigger>
612
+ <Menu
613
+ sx={{
614
+ minWidth: 200
615
+ }}
616
+ >
617
+ <Stack px={2} py={1.5} spacing={0.5}>
618
+ <Typography level="title-sm" fontWeight="bold">
619
+ 김철수
620
+ </Typography>
621
+ <Typography level="body-xs" color="neutral">
622
+ kim@example.com
623
+ </Typography>
624
+ </Stack>
625
+
626
+ <ListDivider />
627
+
628
+ <MenuItem>
629
+ <PersonIcon
630
+ sx={{
631
+ mr: 1
632
+ }}
633
+ />
634
+ 프로필
635
+ </MenuItem>
636
+ <MenuItem>
637
+ <SettingsIcon
638
+ sx={{
639
+ mr: 1
640
+ }}
641
+ />
642
+ 계정 설정
643
+ </MenuItem>
644
+
645
+ <ListDivider />
646
+
647
+ <MenuItem>
648
+ <LogoutIcon
649
+ sx={{
650
+ mr: 1
651
+ }}
652
+ />
653
+ 로그아웃
654
+ </MenuItem>
655
+ </Menu>
656
+ </Dropdown>
359
657
  ```
360
658
 
361
659
  ## Dropdown Nested Menus
@@ -364,39 +662,39 @@ Place multiple Dropdown instances side by side to create menu bar patterns.
364
662
 
365
663
  ```tsx
366
664
  <Stack direction="row" spacing={3}>
367
- <Dropdown>
368
- <MenuButton variant="outlined" endDecorator={<ExpandMoreIcon />}>
369
- 파일
370
- </MenuButton>
371
- <Menu>
372
- <MenuItem>새 파일</MenuItem>
373
- <MenuItem>열기</MenuItem>
374
- <MenuItem disabled>최근 파일</MenuItem>
375
- <ListDivider />
376
- <MenuItem>저장</MenuItem>
377
- <MenuItem>다른 이름으로 저장</MenuItem>
378
- <ListDivider />
379
- <MenuItem>인쇄</MenuItem>
380
- </Menu>
381
- </Dropdown>
665
+ <Dropdown>
666
+ <MenuButtonTrigger variant="outlined" endDecorator={<ExpandMoreIcon />}>
667
+ 파일
668
+ </MenuButtonTrigger>
669
+ <Menu>
670
+ <MenuItem>새 파일</MenuItem>
671
+ <MenuItem>열기</MenuItem>
672
+ <MenuItem disabled>최근 파일</MenuItem>
673
+ <ListDivider />
674
+ <MenuItem>저장</MenuItem>
675
+ <MenuItem>다른 이름으로 저장</MenuItem>
676
+ <ListDivider />
677
+ <MenuItem>인쇄</MenuItem>
678
+ </Menu>
679
+ </Dropdown>
382
680
 
383
- <Dropdown>
384
- <MenuButton variant="outlined" endDecorator={<ExpandMoreIcon />}>
385
- 편집
386
- </MenuButton>
387
- <Menu>
388
- <MenuItem>실행 취소</MenuItem>
389
- <MenuItem>다시 실행</MenuItem>
390
- <ListDivider />
391
- <MenuItem>잘라내기</MenuItem>
392
- <MenuItem>복사</MenuItem>
393
- <MenuItem>붙여넣기</MenuItem>
394
- <ListDivider />
395
- <MenuItem>모두 선택</MenuItem>
396
- <MenuItem>찾기</MenuItem>
397
- </Menu>
398
- </Dropdown>
399
- </Stack>
681
+ <Dropdown>
682
+ <MenuButtonTrigger variant="outlined" endDecorator={<ExpandMoreIcon />}>
683
+ 편집
684
+ </MenuButtonTrigger>
685
+ <Menu>
686
+ <MenuItem>실행 취소</MenuItem>
687
+ <MenuItem>다시 실행</MenuItem>
688
+ <ListDivider />
689
+ <MenuItem>잘라내기</MenuItem>
690
+ <MenuItem>복사</MenuItem>
691
+ <MenuItem>붙여넣기</MenuItem>
692
+ <ListDivider />
693
+ <MenuItem>모두 선택</MenuItem>
694
+ <MenuItem>찾기</MenuItem>
695
+ </Menu>
696
+ </Dropdown>
697
+ </Stack>
400
698
  ```
401
699
 
402
700
  ## Dropdown Controlled State
@@ -405,23 +703,23 @@ Use the `open` and `onOpenChange` props to programmatically control the menu sta
405
703
 
406
704
  ```tsx
407
705
  <Stack spacing={2}>
408
- <Typography level="body-sm">메뉴 상태: {open ? '열림' : '닫힘'}</Typography>
706
+ <Typography level="body-sm">메뉴 상태: {open ? "열림" : "닫힘"}</Typography>
409
707
 
410
- <Dropdown open={open} onOpenChange={(event, isOpen) => setOpen(isOpen)}>
411
- <MenuButton variant="outlined" endDecorator={<ExpandMoreIcon />}>
412
- 제어된 메뉴
413
- </MenuButton>
414
- <Menu>
415
- <MenuItem onClick={() => setOpen(false)}>옵션 1</MenuItem>
416
- <MenuItem onClick={() => setOpen(false)}>옵션 2</MenuItem>
417
- <MenuItem onClick={() => setOpen(false)}>옵션 3</MenuItem>
418
- </Menu>
419
- </Dropdown>
708
+ <Dropdown open={open} onOpenChange={(event, isOpen) => setOpen(isOpen)}>
709
+ <MenuButtonTrigger variant="outlined" endDecorator={<ExpandMoreIcon />}>
710
+ 제어된 메뉴
711
+ </MenuButtonTrigger>
712
+ <Menu>
713
+ <MenuItem onClick={() => setOpen(false)}>옵션 1</MenuItem>
714
+ <MenuItem onClick={() => setOpen(false)}>옵션 2</MenuItem>
715
+ <MenuItem onClick={() => setOpen(false)}>옵션 3</MenuItem>
716
+ </Menu>
717
+ </Dropdown>
420
718
 
421
- <Button variant="soft" size="sm" onClick={() => setOpen(!open)}>
422
- {open ? '메뉴 닫기' : '메뉴 열기'}
423
- </Button>
424
- </Stack>
719
+ <Button variant="soft" size="sm" onClick={() => setOpen(!open)}>
720
+ {open ? "메뉴 닫기" : "메뉴 열기"}
721
+ </Button>
722
+ </Stack>
425
723
  ```
426
724
 
427
725
  ## Dropdown Disabled State
@@ -430,22 +728,22 @@ Disable the entire trigger button or individual menu items.
430
728
 
431
729
  ```tsx
432
730
  <Stack direction="row" spacing={2}>
433
- <Dropdown>
434
- <MenuButton disabled>비활성 메뉴</MenuButton>
435
- <Menu>
436
- <MenuItem>접근 불가</MenuItem>
437
- </Menu>
438
- </Dropdown>
731
+ <Dropdown>
732
+ <MenuButtonTrigger disabled>비활성 메뉴</MenuButtonTrigger>
733
+ <Menu>
734
+ <MenuItem>접근 불가</MenuItem>
735
+ </Menu>
736
+ </Dropdown>
439
737
 
440
- <Dropdown>
441
- <MenuButton variant="outlined">일부 옵션 비활성</MenuButton>
442
- <Menu>
443
- <MenuItem>활성 옵션</MenuItem>
444
- <MenuItem disabled>비활성 옵션</MenuItem>
445
- <MenuItem>활성 옵션 2</MenuItem>
446
- </Menu>
447
- </Dropdown>
448
- </Stack>
738
+ <Dropdown>
739
+ <MenuButtonTrigger variant="outlined">일부 옵션 비활성</MenuButtonTrigger>
740
+ <Menu>
741
+ <MenuItem>활성 옵션</MenuItem>
742
+ <MenuItem disabled>비활성 옵션</MenuItem>
743
+ <MenuItem>활성 옵션 2</MenuItem>
744
+ </Menu>
745
+ </Dropdown>
746
+ </Stack>
449
747
  ```
450
748
 
451
749
  ## Dropdown Long Menu
@@ -454,18 +752,25 @@ Apply `maxHeight` and `overflow: 'auto'` to Menu for scrollable lists with many
454
752
 
455
753
  ```tsx
456
754
  <Dropdown>
457
- <MenuButton variant="outlined" endDecorator={<ExpandMoreIcon />}>
458
- 긴 목록 메뉴
459
- </MenuButton>
460
- <Menu sx={{
461
- maxHeight: 300,
462
- overflow: 'auto'
463
- }}>
464
- {Array.from({
465
- length: 20
466
- }, (_, index) => <MenuItem key={index}>옵션 {index + 1}</MenuItem>)}
467
- </Menu>
468
- </Dropdown>
755
+ <MenuButtonTrigger variant="outlined" endDecorator={<ExpandMoreIcon />}>
756
+ 긴 목록 메뉴
757
+ </MenuButtonTrigger>
758
+ <Menu
759
+ sx={{
760
+ maxHeight: 300,
761
+ overflow: "auto"
762
+ }}
763
+ >
764
+ {Array.from(
765
+ {
766
+ length: 20
767
+ },
768
+ (_, index) => (
769
+ <MenuItem key={index}>옵션 {index + 1}</MenuItem>
770
+ )
771
+ )}
772
+ </Menu>
773
+ </Dropdown>
469
774
  ```
470
775
 
471
776
  ## Dropdown Custom Styling
@@ -474,68 +779,98 @@ Customize borders, shadows, border-radius, and gradients through the `sx` prop.
474
779
 
475
780
  ```tsx
476
781
  <Stack direction="row" spacing={2}>
477
- <Dropdown>
478
- <MenuButton variant="soft" color="primary" endDecorator={<ExpandMoreIcon />} sx={{
479
- borderRadius: 'xl',
480
- fontWeight: 'bold'
481
- }}>
482
- 커스텀 버튼
483
- </MenuButton>
484
- <Menu sx={{
485
- borderRadius: 'md',
486
- boxShadow: 'lg',
487
- border: '2px solid',
488
- borderColor: 'primary.200'
489
- }}>
490
- <MenuItem sx={{
491
- borderRadius: 'sm',
492
- mx: 0.5,
493
- my: 0.25
494
- }}>둥근 아이템 1</MenuItem>
495
- <MenuItem sx={{
496
- borderRadius: 'sm',
497
- mx: 0.5,
498
- my: 0.25
499
- }}>둥근 아이템 2</MenuItem>
500
- <MenuItem sx={{
501
- borderRadius: 'sm',
502
- mx: 0.5,
503
- my: 0.25
504
- }}>둥근 아이템 3</MenuItem>
505
- </Menu>
506
- </Dropdown>
782
+ <Dropdown>
783
+ <MenuButtonTrigger
784
+ variant="soft"
785
+ color="primary"
786
+ endDecorator={<ExpandMoreIcon />}
787
+ sx={{
788
+ borderRadius: "xl",
789
+ fontWeight: "bold"
790
+ }}
791
+ >
792
+ 커스텀 버튼
793
+ </MenuButtonTrigger>
794
+ <Menu
795
+ sx={{
796
+ borderRadius: "md",
797
+ boxShadow: "lg",
798
+ border: "2px solid",
799
+ borderColor: "primary.200"
800
+ }}
801
+ >
802
+ <MenuItem
803
+ sx={{
804
+ borderRadius: "sm",
805
+ mx: 0.5,
806
+ my: 0.25
807
+ }}
808
+ >
809
+ 둥근 아이템 1
810
+ </MenuItem>
811
+ <MenuItem
812
+ sx={{
813
+ borderRadius: "sm",
814
+ mx: 0.5,
815
+ my: 0.25
816
+ }}
817
+ >
818
+ 둥근 아이템 2
819
+ </MenuItem>
820
+ <MenuItem
821
+ sx={{
822
+ borderRadius: "sm",
823
+ mx: 0.5,
824
+ my: 0.25
825
+ }}
826
+ >
827
+ 둥근 아이템 3
828
+ </MenuItem>
829
+ </Menu>
830
+ </Dropdown>
507
831
 
508
- <Dropdown>
509
- <MenuButton variant="outlined" sx={{
510
- background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
511
- border: 0,
512
- borderRadius: 3,
513
- color: 'white',
514
- '&:hover': {
515
- background: 'linear-gradient(45deg, #FE6B8B 60%, #FF8E53 100%)'
516
- }
517
- }}>
518
- 그라데이션 버튼
519
- </MenuButton>
520
- <Menu>
521
- <MenuItem>스타일링된 메뉴</MenuItem>
522
- <MenuItem>아이템 2</MenuItem>
523
- </Menu>
524
- </Dropdown>
525
- </Stack>
832
+ <Dropdown>
833
+ <MenuButtonTrigger
834
+ variant="outlined"
835
+ sx={{
836
+ background: "linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)",
837
+ border: 0,
838
+ borderRadius: 3,
839
+ color: "white",
840
+ "&:hover": {
841
+ background: "linear-gradient(45deg, #FE6B8B 60%, #FF8E53 100%)"
842
+ }
843
+ }}
844
+ >
845
+ 그라데이션 버튼
846
+ </MenuButtonTrigger>
847
+ <Menu>
848
+ <MenuItem>스타일링된 메뉴</MenuItem>
849
+ <MenuItem>아이템 2</MenuItem>
850
+ </Menu>
851
+ </Dropdown>
852
+ </Stack>
526
853
  ```
527
854
 
528
855
  ## Navigation Menu
529
856
 
530
857
  ```tsx
531
858
  <Dropdown>
532
- <MenuButton variant="plain">Menu</MenuButton>
859
+ <MenuButtonTrigger variant="plain">Menu</MenuButtonTrigger>
533
860
  <Menu>
534
- <MenuItem component="a" href="/home">Home</MenuItem>
535
- <MenuItem component="a" href="/about">About</MenuItem>
536
- <MenuItem component="a" href="/products">Products</MenuItem>
861
+ <MenuItem component="a" href="/home">
862
+ Home
863
+ </MenuItem>
864
+ <MenuItem component="a" href="/about">
865
+ About
866
+ </MenuItem>
867
+ <MenuItem component="a" href="/products">
868
+ Products
869
+ </MenuItem>
537
870
  <ListDivider />
538
- <MenuItem component="a" href="/contact">Contact</MenuItem>
871
+ <MenuItem component="a" href="/contact">
872
+ Contact
873
+ </MenuItem>
539
874
  </Menu>
540
875
  </Dropdown>
541
876
  ```
@@ -546,19 +881,15 @@ Customize borders, shadows, border-radius, and gradients through the `sx` prop.
546
881
  const [filter, setFilter] = useState('All');
547
882
 
548
883
  <Dropdown>
549
- <MenuButton
550
- variant="outlined"
551
- startDecorator={<FilterListIcon />}
552
- endDecorator={<ExpandMoreIcon />}
553
- >
884
+ <MenuButtonTrigger variant="outlined" startDecorator={<FilterListIcon />} endDecorator={<ExpandMoreIcon />}>
554
885
  Filter: {filter}
555
- </MenuButton>
886
+ </MenuButtonTrigger>
556
887
  <Menu>
557
888
  <MenuItem onClick={() => setFilter('All')}>All</MenuItem>
558
889
  <MenuItem onClick={() => setFilter('Active')}>Active</MenuItem>
559
890
  <MenuItem onClick={() => setFilter('Inactive')}>Inactive</MenuItem>
560
891
  </Menu>
561
- </Dropdown>
892
+ </Dropdown>;
562
893
  ```
563
894
 
564
895
  ## Controlled State with External Toggle
@@ -567,7 +898,7 @@ const [filter, setFilter] = useState('All');
567
898
  const [open, setOpen] = useState(false);
568
899
 
569
900
  <Dropdown open={open} onOpenChange={(event, isOpen) => setOpen(isOpen)}>
570
- <MenuButton>Controlled Menu</MenuButton>
901
+ <MenuButtonTrigger>Controlled Menu</MenuButtonTrigger>
571
902
  <Menu>
572
903
  <MenuItem onClick={() => setOpen(false)}>Option A</MenuItem>
573
904
  <MenuItem onClick={() => setOpen(false)}>Option B</MenuItem>
@@ -583,26 +914,30 @@ const [open, setOpen] = useState(false);
583
914
 
584
915
  ### Key Props
585
916
 
586
- | Prop | Type | Default | Description |
587
- | -------------- | -------------------------------- | ------- | ------------------------------------ |
588
- | `children` | `ReactNode` | - | Dropdown content (MenuButton + Menu) |
589
- | `open` | `boolean` | - | Controlled open state |
590
- | `defaultOpen` | `boolean` | `false` | Initial open state (uncontrolled) |
591
- | `onOpenChange` | `(event, open: boolean) => void` | - | Callback when open state changes |
917
+ | Prop | Type | Default | Description |
918
+ | -------------- | -------------------------------- | ------- | ------------------------------------------- |
919
+ | `children` | `ReactNode` | - | Dropdown content (MenuButtonTrigger + Menu) |
920
+ | `open` | `boolean` | - | Controlled open state |
921
+ | `defaultOpen` | `boolean` | `false` | Initial open state (uncontrolled) |
922
+ | `onOpenChange` | `(event, open: boolean) => void` | - | Callback when open state changes |
592
923
 
593
- > **Note**: Dropdown accepts all Joy UI Dropdown props. It is a state management wrapper — style props go on Menu and MenuButton.
924
+ > **Note**: Dropdown accepts all Joy UI Dropdown props. It is a state management wrapper — style props go on Menu and `MenuButtonTrigger`.
594
925
 
595
926
  ## Best Practices
596
927
 
597
928
  - **Use the right abstraction level.** If you only need a simple list of text items, prefer `MenuButton` or `IconMenuButton` standalone components. Use `Dropdown` + `Menu` when you need dividers, custom headers, or mixed content inside the menu.
598
929
 
599
930
  ```tsx
600
- {/* ✅ Good: Simple list -- use MenuButton directly */}
601
- <MenuButton buttonText="Actions" items={[{ text: 'Edit' }, { text: 'Delete' }]} />
602
-
603
- {/* ✅ Good: Complex content -- use Dropdown composition */}
931
+ {
932
+ /* Good: Simple list -- use MenuButton directly */
933
+ }
934
+ <MenuButton buttonText="Actions" items={[{ text: 'Edit' }, { text: 'Delete' }]} />;
935
+
936
+ {
937
+ /* ✅ Good: Complex content -- use Dropdown composition */
938
+ }
604
939
  <Dropdown>
605
- <MenuButton>User</MenuButton>
940
+ <MenuButtonTrigger>User</MenuButtonTrigger>
606
941
  <Menu>
607
942
  <Box sx={{ px: 2, py: 1 }}>
608
943
  <Typography level="title-sm">User Name</Typography>
@@ -611,29 +946,35 @@ const [open, setOpen] = useState(false);
611
946
  <MenuItem>Settings</MenuItem>
612
947
  <MenuItem>Logout</MenuItem>
613
948
  </Menu>
614
- </Dropdown>
949
+ </Dropdown>;
615
950
  ```
616
951
 
617
952
  - **Group related items with ListDivider.** Visually separate logical groups of menu items so users can scan options quickly.
618
953
 
619
954
  ```tsx
620
- {/* ✅ Good: Grouped by function */}
955
+ {
956
+ /* ✅ Good: Grouped by function */
957
+ }
621
958
  <Menu>
622
959
  <MenuItem>Edit</MenuItem>
623
960
  <MenuItem>Duplicate</MenuItem>
624
961
  <ListDivider />
625
962
  <MenuItem color="danger">Delete</MenuItem>
626
- </Menu>
963
+ </Menu>;
627
964
  ```
628
965
 
629
966
  - **Indicate dropdown affordance.** Use `endDecorator={<ExpandMoreIcon />}` on the trigger button so users understand it opens a menu.
630
967
 
631
968
  ```tsx
632
- {/* ✅ Good: Clear dropdown indicator */}
633
- <MenuButton endDecorator={<ExpandMoreIcon />}>Options</MenuButton>
634
-
635
- {/* ❌ Avoid: No visual hint that a menu will appear */}
636
- <MenuButton>Options</MenuButton>
969
+ {
970
+ /* Good: Clear dropdown indicator */
971
+ }
972
+ <MenuButtonTrigger endDecorator={<ExpandMoreIcon />}>Options</MenuButtonTrigger>;
973
+
974
+ {
975
+ /* ❌ Avoid: No visual hint that a menu will appear */
976
+ }
977
+ <MenuButtonTrigger>Options</MenuButtonTrigger>;
637
978
  ```
638
979
 
639
980
  - **Keep menu item count reasonable.** Aim for 3-7 items. For longer lists, apply `maxHeight` with scrolling or consider a different UI pattern like a dialog or searchable list.