@ceed/ads 1.23.3 → 1.23.5

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 (43) hide show
  1. package/dist/components/data-display/Badge.md +71 -39
  2. package/dist/components/data-display/InfoSign.md +74 -98
  3. package/dist/components/data-display/Typography.md +310 -61
  4. package/dist/components/feedback/CircularProgress.md +257 -0
  5. package/dist/components/feedback/Skeleton.md +280 -0
  6. package/dist/components/feedback/llms.txt +2 -0
  7. package/dist/components/inputs/ButtonGroup.md +115 -106
  8. package/dist/components/inputs/Calendar.md +98 -459
  9. package/dist/components/inputs/CurrencyInput.md +181 -8
  10. package/dist/components/inputs/DatePicker.md +108 -436
  11. package/dist/components/inputs/DateRangePicker.md +130 -496
  12. package/dist/components/inputs/FilterMenu.md +169 -19
  13. package/dist/components/inputs/FilterableCheckboxGroup.md +119 -24
  14. package/dist/components/inputs/FormControl.md +361 -0
  15. package/dist/components/inputs/IconButton.md +137 -88
  16. package/dist/components/inputs/MonthPicker.md +95 -427
  17. package/dist/components/inputs/MonthRangePicker.md +89 -471
  18. package/dist/components/inputs/PercentageInput.md +183 -19
  19. package/dist/components/inputs/RadioButton.md +163 -35
  20. package/dist/components/inputs/RadioList.md +241 -0
  21. package/dist/components/inputs/RadioTileGroup.md +146 -62
  22. package/dist/components/inputs/Select.md +219 -328
  23. package/dist/components/inputs/Slider.md +334 -0
  24. package/dist/components/inputs/Switch.md +136 -376
  25. package/dist/components/inputs/Textarea.md +209 -11
  26. package/dist/components/inputs/Uploader/Uploader.md +145 -66
  27. package/dist/components/inputs/llms.txt +3 -0
  28. package/dist/components/navigation/Breadcrumbs.md +80 -322
  29. package/dist/components/navigation/Dropdown.md +92 -221
  30. package/dist/components/navigation/IconMenuButton.md +40 -502
  31. package/dist/components/navigation/InsetDrawer.md +68 -738
  32. package/dist/components/navigation/Link.md +39 -298
  33. package/dist/components/navigation/Menu.md +92 -285
  34. package/dist/components/navigation/MenuButton.md +55 -448
  35. package/dist/components/navigation/Pagination.md +47 -338
  36. package/dist/components/navigation/ProfileMenu.md +45 -268
  37. package/dist/components/navigation/Stepper.md +160 -28
  38. package/dist/components/navigation/Tabs.md +57 -316
  39. package/dist/components/surfaces/Sheet.md +150 -333
  40. package/dist/guides/ThemeProvider.md +116 -0
  41. package/dist/guides/llms.txt +9 -0
  42. package/dist/llms.txt +8 -0
  43. package/package.json +1 -1
@@ -0,0 +1,280 @@
1
+ # Skeleton
2
+
3
+ ## Introduction
4
+
5
+ The Skeleton component provides placeholder previews of content before data is loaded. It is based on Joy UI's Skeleton and helps reduce perceived loading time by showing an approximation of the page layout. Skeletons improve the user experience by preventing layout shifts and giving users a visual cue that content is on its way.
6
+
7
+ ```tsx
8
+ <Skeleton
9
+ variant="rectangular"
10
+ width={200}
11
+ height={24}
12
+ />
13
+ ```
14
+
15
+ | Field | Description | Default |
16
+ | ---------------------------- | ----------- | ------- |
17
+ | Controls resolved at runtime | — | — |
18
+
19
+ ## Usage
20
+
21
+ ```tsx
22
+ import { Skeleton } from '@ceed/ads';
23
+
24
+ function MyComponent() {
25
+ return <Skeleton variant="rectangular" width={200} height={24} />;
26
+ }
27
+ ```
28
+
29
+ ## Variants
30
+
31
+ Skeleton supports three variants: `rectangular`, `circular`, and `text`.
32
+
33
+ - **rectangular**: Block-shaped placeholder for images, cards, and content areas.
34
+ - **circular**: Round placeholder for avatars and icons.
35
+ - **text**: Matches the height and spacing of text content at a given `level`.
36
+
37
+ ```tsx
38
+ <>
39
+ <Skeleton variant="rectangular" width={200} height={24} />
40
+ <Skeleton variant="circular" width={48} height={48} />
41
+ <Skeleton variant="text" width={200} />
42
+ </>
43
+ ```
44
+
45
+ ```tsx
46
+ <Skeleton variant="rectangular" width={200} height={24} />
47
+ <Skeleton variant="circular" width={48} height={48} />
48
+ <Skeleton variant="text" width={200} />
49
+ ```
50
+
51
+ ## Animations
52
+
53
+ Skeleton supports `wave` (default) and `pulse` animations. Set `animation={false}` to disable animation entirely.
54
+
55
+ ```tsx
56
+ <Stack gap={3}>
57
+ <Box>
58
+ <Typography level="body-sm" sx={{
59
+ mb: 1
60
+ }}>
61
+ Wave (default)
62
+ </Typography>
63
+ <Skeleton animation="wave" variant="rectangular" width={200} height={24} />
64
+ </Box>
65
+ <Box>
66
+ <Typography level="body-sm" sx={{
67
+ mb: 1
68
+ }}>
69
+ Pulse
70
+ </Typography>
71
+ <Skeleton animation="pulse" variant="rectangular" width={200} height={24} />
72
+ </Box>
73
+ <Box>
74
+ <Typography level="body-sm" sx={{
75
+ mb: 1
76
+ }}>
77
+ No animation (false)
78
+ </Typography>
79
+ <Skeleton animation={false} variant="rectangular" width={200} height={24} />
80
+ </Box>
81
+ </Stack>
82
+ ```
83
+
84
+ ```tsx
85
+ <Skeleton animation="wave" variant="rectangular" width={200} height={24} />
86
+ <Skeleton animation="pulse" variant="rectangular" width={200} height={24} />
87
+ <Skeleton animation={false} variant="rectangular" width={200} height={24} />
88
+ ```
89
+
90
+ ## Text Skeleton
91
+
92
+ Use `variant="text"` with the `level` prop to match Typography sizing. This is useful for creating text content placeholders that accurately reflect the final layout.
93
+
94
+ ```tsx
95
+ <Stack gap={1} sx={{
96
+ width: 300
97
+ }}>
98
+ <Skeleton variant="text" level="h3" />
99
+ <Skeleton variant="text" level="body-md" />
100
+ <Skeleton variant="text" level="body-md" />
101
+ <Skeleton variant="text" level="body-md" width="80%" />
102
+ </Stack>
103
+ ```
104
+
105
+ ```tsx
106
+ <Skeleton variant="text" level="h3" />
107
+ <Skeleton variant="text" level="body-md" />
108
+ <Skeleton variant="text" level="body-md" />
109
+ <Skeleton variant="text" level="body-md" width="80%" />
110
+ ```
111
+
112
+ ## Card Skeleton
113
+
114
+ Compose multiple Skeleton elements to create placeholder layouts for complex components like cards.
115
+
116
+ ```tsx
117
+ <Box sx={{
118
+ width: 300,
119
+ p: 2,
120
+ border: '1px solid',
121
+ borderColor: 'divider',
122
+ borderRadius: 'sm'
123
+ }}>
124
+ <Skeleton variant="rectangular" width="100%" height={140} sx={{
125
+ borderRadius: 'sm',
126
+ mb: 2
127
+ }} />
128
+ <Skeleton variant="text" level="title-md" sx={{
129
+ mb: 1
130
+ }} />
131
+ <Skeleton variant="text" level="body-sm" />
132
+ <Skeleton variant="text" level="body-sm" width="60%" />
133
+ <Stack direction="row" gap={1} sx={{
134
+ mt: 2
135
+ }}>
136
+ <Skeleton variant="rectangular" width={80} height={32} sx={{
137
+ borderRadius: 'sm'
138
+ }} />
139
+ <Skeleton variant="rectangular" width={80} height={32} sx={{
140
+ borderRadius: 'sm'
141
+ }} />
142
+ </Stack>
143
+ </Box>
144
+ ```
145
+
146
+ ## Data Loading List
147
+
148
+ Combine circular and text skeletons to represent list items during loading.
149
+
150
+ ```tsx
151
+ <Stack gap={2} sx={{
152
+ width: 400
153
+ }}>
154
+ {[1, 2, 3].map(i => <Stack key={i} direction="row" gap={2} alignItems="center">
155
+ <Skeleton variant="circular" width={40} height={40} />
156
+ <Box sx={{
157
+ flex: 1
158
+ }}>
159
+ <Skeleton variant="text" level="title-sm" width="60%" />
160
+ <Skeleton variant="text" level="body-xs" width="40%" />
161
+ </Box>
162
+ </Stack>)}
163
+ </Stack>
164
+ ```
165
+
166
+ ## Inline Wrapping
167
+
168
+ Wrap existing content with Skeleton to overlay it while loading. Set the `loading` prop to control visibility.
169
+
170
+ ```tsx
171
+ <Typography level="body-md">
172
+ <Skeleton loading>
173
+ This text will be hidden behind a skeleton while loading.
174
+ </Skeleton>
175
+ </Typography>
176
+ ```
177
+
178
+ ```tsx
179
+ <Typography level="body-md">
180
+ <Skeleton loading>
181
+ This text will be hidden behind a skeleton while loading.
182
+ </Skeleton>
183
+ </Typography>
184
+ ```
185
+
186
+ ## Common Use Cases
187
+
188
+ ### Page Content Loading
189
+
190
+ ```tsx
191
+ function PageSkeleton() {
192
+ return (
193
+ <Stack gap={3}>
194
+ <Skeleton variant="text" level="h1" width="50%" />
195
+ <Skeleton variant="text" level="body-md" />
196
+ <Skeleton variant="text" level="body-md" />
197
+ <Skeleton variant="text" level="body-md" width="75%" />
198
+
199
+ <Skeleton variant="rectangular" width="100%" height={200} sx={{ borderRadius: 'sm' }} />
200
+
201
+ <Skeleton variant="text" level="body-md" />
202
+ <Skeleton variant="text" level="body-md" />
203
+ </Stack>
204
+ );
205
+ }
206
+ ```
207
+
208
+ ### User List Loading
209
+
210
+ ```tsx
211
+ function UserListSkeleton({ count = 5 }: { count?: number }) {
212
+ return (
213
+ <Stack gap={2}>
214
+ {Array.from({ length: count }).map((_, i) => (
215
+ <Stack key={i} direction="row" gap={2} alignItems="center">
216
+ <Skeleton variant="circular" width={40} height={40} />
217
+ <Box sx={{ flex: 1 }}>
218
+ <Skeleton variant="text" level="title-sm" width="40%" />
219
+ <Skeleton variant="text" level="body-xs" width="25%" />
220
+ </Box>
221
+ </Stack>
222
+ ))}
223
+ </Stack>
224
+ );
225
+ }
226
+ ```
227
+
228
+ ### Conditional Rendering
229
+
230
+ ```tsx
231
+ function UserProfile({ loading, user }: { loading: boolean; user?: User }) {
232
+ return (
233
+ <Stack direction="row" gap={2} alignItems="center">
234
+ {loading ? (
235
+ <Skeleton variant="circular" width={48} height={48} />
236
+ ) : (
237
+ <Avatar src={user?.avatar} />
238
+ )}
239
+ <Box>
240
+ <Typography level="title-md">
241
+ <Skeleton loading={loading}>{user?.name || 'Placeholder Name'}</Skeleton>
242
+ </Typography>
243
+ <Typography level="body-sm">
244
+ <Skeleton loading={loading}>{user?.email || 'email@example.com'}</Skeleton>
245
+ </Typography>
246
+ </Box>
247
+ </Stack>
248
+ );
249
+ }
250
+ ```
251
+
252
+ ## Best Practices
253
+
254
+ 1. **Match the final layout**: Skeleton placeholders should closely approximate the size and position of the real content to prevent layout shifts.
255
+
256
+ ```tsx
257
+ // ✅ Matches the actual content structure
258
+ <Stack gap={1}>
259
+ <Skeleton variant="text" level="title-md" width="60%" />
260
+ <Skeleton variant="text" level="body-sm" />
261
+ </Stack>
262
+
263
+ // ❌ Generic rectangle that doesn't match
264
+ <Skeleton variant="rectangular" width={300} height={100} />
265
+ ```
266
+
267
+ 2. **Use `variant="text"` with `level`**: When replacing Typography, use the text variant with the matching level to get accurate line heights.
268
+
269
+ 3. **Avoid over-skeletonizing**: Only skeleton the main content areas. Don't add skeletons for static elements like navigation or headers that are always present.
270
+
271
+ 4. **Use consistent animation**: Keep the same animation type (`wave` or `pulse`) across the entire application for a cohesive loading experience.
272
+
273
+ 5. **Set appropriate widths**: Vary skeleton widths (e.g., 60%, 80%, 100%) to mimic natural text line lengths rather than using uniform widths.
274
+
275
+ ## Accessibility
276
+
277
+ - Skeleton elements are purely decorative. Screen readers should focus on the loading state announcement, not individual skeleton elements.
278
+ - Use `aria-busy="true"` on the container element while content is loading.
279
+ - Provide an `aria-label` or visually hidden text that describes the loading state (e.g., "Loading user profile").
280
+ - Ensure the animation respects `prefers-reduced-motion` — Joy UI handles this automatically.
@@ -3,8 +3,10 @@
3
3
  ## Documentation
4
4
 
5
5
  - [Alert](./Alert.md)
6
+ - [CircularProgress](./CircularProgress.md)
6
7
  - [DialogFrame](./Dialog.md)
7
8
  - [Modal](./Modal.md)
9
+ - [Skeleton](./Skeleton.md)
8
10
 
9
11
  ## Parent
10
12
 
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- ButtonGroup 컴포넌트는 관련된 버튼들을 그룹화하여 하나의 통합된 인터페이스로 표시합니다. 버튼들을 논리적으로 묶어서 시각적 일관성을 제공하고, 공간을 효율적으로 사용할 있게 해줍니다. 툴바, 액션 버튼 세트, 토글 그룹 등에 주로 사용됩니다.
5
+ ButtonGroup is a layout component that visually and semantically groups related buttons into a single cohesive unit. It automatically handles border merging, spacing, and consistent styling across all child buttons, making it ideal for toolbars, action sets, and segmented controls.
6
+
7
+ By applying shared props like `color`, `variant`, `size`, and `orientation` at the group level, you ensure visual consistency without having to repeat props on every individual button. ButtonGroup is built on top of Joy UI's ButtonGroup and inherits all of its capabilities.
6
8
 
7
9
  ```tsx
8
10
  <ButtonGroup {...args}>
@@ -28,37 +30,17 @@ import { ButtonGroup, Button } from '@ceed/ads';
28
30
  function MyComponent() {
29
31
  return (
30
32
  <ButtonGroup>
31
- <Button>첫번째</Button>
32
- <Button>두번째</Button>
33
- <Button>세번째</Button>
33
+ <Button>First</Button>
34
+ <Button>Second</Button>
35
+ <Button>Third</Button>
34
36
  </ButtonGroup>
35
37
  );
36
38
  }
37
39
  ```
38
40
 
39
- ## Examples
40
-
41
- ### Basic Usage
41
+ ## Colors
42
42
 
43
- 기본적인 ButtonGroup 사용법입니다.
44
-
45
- ```tsx
46
- <div style={{
47
- display: 'flex',
48
- gap: '2rem',
49
- flexDirection: 'column'
50
- }}>
51
- <ButtonGroup>
52
- <Button>첫번째</Button>
53
- <Button>두번째</Button>
54
- <Button>세번째</Button>
55
- </ButtonGroup>
56
- </div>
57
- ```
58
-
59
- ### Colors
60
-
61
- 다양한 색상을 적용할 수 있습니다.
43
+ Apply a unified color theme to all buttons in the group using the `color` prop. Available colors are `primary`, `neutral`, `danger`, `success`, and `warning`.
62
44
 
63
45
  ```tsx
64
46
  <div style={{
@@ -98,9 +80,9 @@ function MyComponent() {
98
80
  </div>
99
81
  ```
100
82
 
101
- ### Variants
83
+ ## Variants
102
84
 
103
- 다양한 스타일 변형을 제공합니다.
85
+ ButtonGroup supports four visual variants: `solid`, `soft`, `outlined`, and `plain`. The variant prop propagates to all child buttons, ensuring a consistent look.
104
86
 
105
87
  ```tsx
106
88
  <div style={{
@@ -134,9 +116,9 @@ function MyComponent() {
134
116
  </div>
135
117
  ```
136
118
 
137
- ### Sizes
119
+ ## Sizes
138
120
 
139
- 크기를 조절할 있습니다.
121
+ Control the size of all buttons in the group with the `size` prop. Available sizes are `sm`, `md` (default), and `lg`.
140
122
 
141
123
  ```tsx
142
124
  <div style={{
@@ -165,9 +147,9 @@ function MyComponent() {
165
147
  </div>
166
148
  ```
167
149
 
168
- ### Orientations
150
+ ## Orientations
169
151
 
170
- 수평(horizontal) 또는 수직(vertical) 방향으로 배치할 있습니다.
152
+ Buttons can be arranged horizontally (default) or vertically. Use `orientation="vertical"` for stacked layouts such as side panels or narrow containers.
171
153
 
172
154
  ```tsx
173
155
  <div style={{
@@ -195,9 +177,9 @@ function MyComponent() {
195
177
  </div>
196
178
  ```
197
179
 
198
- ### With Icons
180
+ ## With Icons
199
181
 
200
- 아이콘과 함께 사용할 있습니다.
182
+ Combine text labels with icons using the `startDecorator` prop on individual buttons for a richer, more descriptive interface.
201
183
 
202
184
  ```tsx
203
185
  <div style={{
@@ -219,49 +201,9 @@ function MyComponent() {
219
201
  </div>
220
202
  ```
221
203
 
222
- ### Action Groups
223
-
224
- 실제 사용 사례별 액션 그룹들입니다.
225
-
226
- ```tsx
227
- <div style={{
228
- display: 'flex',
229
- gap: '2rem',
230
- flexDirection: 'column'
231
- }}>
232
- <div>
233
- <h4>File Actions</h4>
234
- <ButtonGroup variant="outlined">
235
- <Button onClick={() => alert('Save')}>저장</Button>
236
- <Button onClick={() => alert('Save As')}>다른 이름으로 저장</Button>
237
- <Button onClick={() => alert('Export')}>내보내기</Button>
238
- </ButtonGroup>
239
- </div>
240
-
241
- <div>
242
- <h4>Text Formatting</h4>
243
- <ButtonGroup size="sm" variant="soft">
244
- <Button>B</Button>
245
- <Button>I</Button>
246
- <Button>U</Button>
247
- <Button>S</Button>
248
- </ButtonGroup>
249
- </div>
250
-
251
- <div>
252
- <h4>View Options</h4>
253
- <ButtonGroup color="neutral" variant="outlined">
254
- <Button>목록</Button>
255
- <Button>격자</Button>
256
- <Button>타일</Button>
257
- </ButtonGroup>
258
- </div>
259
- </div>
260
- ```
261
-
262
- ### States
204
+ ## States
263
205
 
264
- 다양한 상태를 표현할 있습니다.
206
+ ButtonGroup supports disabled states at the group level (affecting all children) or on individual buttons for mixed-state scenarios.
265
207
 
266
208
  ```tsx
267
209
  <div style={{
@@ -298,9 +240,9 @@ function MyComponent() {
298
240
  </div>
299
241
  ```
300
242
 
301
- ### Toggle Group
243
+ ## Toggle Group
302
244
 
303
- 선택 상태를 토글할 있는 버튼 그룹입니다.
245
+ By dynamically switching the `variant` prop on individual buttons based on selection state, you can create a segmented toggle control for exclusive selection patterns.
304
246
 
305
247
  ```tsx
306
248
  <div>
@@ -325,58 +267,125 @@ function MyComponent() {
325
267
  ### Toolbar Actions
326
268
 
327
269
  ```tsx
270
+ import { ButtonGroup, Button } from '@ceed/ads';
271
+ import SaveIcon from '@mui/icons-material/Save';
272
+ import UndoIcon from '@mui/icons-material/Undo';
273
+ import RedoIcon from '@mui/icons-material/Redo';
274
+
328
275
  <ButtonGroup variant="outlined">
329
- <Button startDecorator={<SaveIcon />}>저장</Button>
330
- <Button startDecorator={<UndoIcon />}>실행 취소</Button>
331
- <Button startDecorator={<RedoIcon />}>다시 실행</Button>
276
+ <Button startDecorator={<SaveIcon />}>Save</Button>
277
+ <Button startDecorator={<UndoIcon />}>Undo</Button>
278
+ <Button startDecorator={<RedoIcon />}>Redo</Button>
332
279
  </ButtonGroup>
333
280
  ```
334
281
 
335
- ### Text Formatting
282
+ ### View Switcher
336
283
 
337
284
  ```tsx
338
- <ButtonGroup size="sm" variant="soft">
339
- <Button onClick={() => format('bold')}>B</Button>
340
- <Button onClick={() => format('italic')}>I</Button>
341
- <Button onClick={() => format('underline')}>U</Button>
285
+ const [view, setView] = useState('list');
286
+
287
+ <ButtonGroup variant="outlined" color="neutral">
288
+ <Button
289
+ variant={view === 'list' ? 'solid' : 'outlined'}
290
+ onClick={() => setView('list')}
291
+ >
292
+ List
293
+ </Button>
294
+ <Button
295
+ variant={view === 'grid' ? 'solid' : 'outlined'}
296
+ onClick={() => setView('grid')}
297
+ >
298
+ Grid
299
+ </Button>
300
+ <Button
301
+ variant={view === 'card' ? 'solid' : 'outlined'}
302
+ onClick={() => setView('card')}
303
+ >
304
+ Card
305
+ </Button>
342
306
  </ButtonGroup>
343
307
  ```
344
308
 
345
- ### View Controls
309
+ ### Pagination Controls
346
310
 
347
311
  ```tsx
348
- <ButtonGroup color="neutral">
349
- <Button onClick={() => setView('list')}>목록</Button>
350
- <Button onClick={() => setView('grid')}>격자</Button>
351
- <Button onClick={() => setView('card')}>카드</Button>
312
+ <ButtonGroup variant="outlined" size="sm">
313
+ <Button disabled={page === 1} onClick={() => setPage(page - 1)}>
314
+ Previous
315
+ </Button>
316
+ <Button disabled>{page}</Button>
317
+ <Button onClick={() => setPage(page + 1)}>
318
+ Next
319
+ </Button>
352
320
  </ButtonGroup>
353
321
  ```
354
322
 
355
- ### Pagination
323
+ ## Best Practices
324
+
325
+ 1. **Group only related actions together.** Each ButtonGroup should represent a logically connected set of operations.
356
326
 
357
327
  ```tsx
328
+ // ✅ Related file operations grouped together
358
329
  <ButtonGroup variant="outlined">
359
- <Button disabled={page === 1} onClick={() => setPage(page - 1)}>
360
- 이전
361
- </Button>
362
- <Button onClick={() => setPage(page + 1)}>
363
- 다음
364
- </Button>
330
+ <Button>Save</Button>
331
+ <Button>Save As</Button>
332
+ <Button>Export</Button>
333
+ </ButtonGroup>
334
+
335
+ // ❌ Unrelated actions mixed in one group
336
+ <ButtonGroup>
337
+ <Button>Save</Button>
338
+ <Button>Delete Account</Button>
339
+ <Button>Help</Button>
365
340
  </ButtonGroup>
366
341
  ```
367
342
 
368
- ## Best Practices
343
+ 2. **Keep the button count between 2 and 5.** Too many buttons reduce clarity and overwhelm users.
344
+
345
+ ```tsx
346
+ // ✅ Concise group
347
+ <ButtonGroup>
348
+ <Button>Bold</Button>
349
+ <Button>Italic</Button>
350
+ <Button>Underline</Button>
351
+ </ButtonGroup>
369
352
 
370
- 1. **관련성**: 논리적으로 관련된 버튼들만 그룹화하세요.
353
+ // Too many options in a single group
354
+ <ButtonGroup>
355
+ <Button>Bold</Button>
356
+ <Button>Italic</Button>
357
+ <Button>Underline</Button>
358
+ <Button>Strikethrough</Button>
359
+ <Button>Superscript</Button>
360
+ <Button>Subscript</Button>
361
+ <Button>Code</Button>
362
+ </ButtonGroup>
363
+ ```
371
364
 
372
- 2. **일관성**: 그룹 내의 모든 버튼은 동일한 variant, size, color를 사용하는 것이 좋습니다.
365
+ 3. **Use consistent variant and color across the group.** Avoid overriding individual button styles unless implementing toggle selection.
373
366
 
374
- 3. **적절한 개수**: 너무 많은 버튼을 한 그룹에 포함하지 마세요. 일반적으로 2-5개가 적당합니다.
367
+ ```tsx
368
+ // ✅ Consistent styling via group props
369
+ <ButtonGroup variant="outlined" color="neutral">
370
+ <Button>A</Button>
371
+ <Button>B</Button>
372
+ </ButtonGroup>
373
+
374
+ // ❌ Mixed styles with no semantic reason
375
+ <ButtonGroup>
376
+ <Button variant="solid">A</Button>
377
+ <Button variant="outlined">B</Button>
378
+ <Button variant="plain">C</Button>
379
+ </ButtonGroup>
380
+ ```
375
381
 
376
- 4. **명확한 레이블**: 버튼의 기능을 명확하게 있는 레이블을 사용하세요.
382
+ 4. **Clearly indicate the active state in toggle groups.** Use a distinct variant (e.g., `solid` vs `outlined`) so users can immediately see which option is selected.
377
383
 
378
- 5. **접근성**: 키보드 탐색이 가능하도록 하고, 스크린 리더를 위한 적절한 레이블을 제공하세요.
384
+ 5. **Consider vertical orientation for narrow layouts.** On mobile or in sidebars, `orientation="vertical"` prevents horizontal overflow and improves usability.
379
385
 
380
- 6. **상태 관리**: 토글 그룹으로 사용할 때는 현재 선택된 상태를 시각적으로 명확히 표시하세요.
386
+ ## Accessibility
381
387
 
382
- 7. **반응형 디자인**: 작은 화면에서는 vertical orientation을 고려하거나 적절한 줄바꿈을 제공하세요.
388
+ - **Keyboard navigation**: All buttons within the group are focusable and navigable using the `Tab` key. Each button is a standard focusable element that responds to `Enter` and `Space`.
389
+ - **ARIA grouping**: Wrap the ButtonGroup in a container with `role="group"` and an `aria-label` when the group represents a distinct set of controls (e.g., text formatting toolbar).
390
+ - **Disabled state**: When the entire group is disabled, all child buttons receive `aria-disabled="true"` automatically, preventing interaction and communicating the state to assistive technologies.
391
+ - **Toggle groups**: When using ButtonGroup as a toggle, consider adding `aria-pressed` to each button to communicate the selection state to screen readers.