@ceed/ads 1.23.2 โ†’ 1.23.4

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 (45) 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/Dialog.md +8 -4
  6. package/dist/components/feedback/Modal.md +7 -3
  7. package/dist/components/feedback/Skeleton.md +280 -0
  8. package/dist/components/feedback/llms.txt +2 -0
  9. package/dist/components/inputs/ButtonGroup.md +115 -106
  10. package/dist/components/inputs/Calendar.md +98 -459
  11. package/dist/components/inputs/CurrencyInput.md +181 -8
  12. package/dist/components/inputs/DatePicker.md +108 -436
  13. package/dist/components/inputs/DateRangePicker.md +130 -496
  14. package/dist/components/inputs/FilterMenu.md +169 -19
  15. package/dist/components/inputs/FilterableCheckboxGroup.md +119 -24
  16. package/dist/components/inputs/FormControl.md +368 -0
  17. package/dist/components/inputs/IconButton.md +137 -88
  18. package/dist/components/inputs/MonthPicker.md +95 -427
  19. package/dist/components/inputs/MonthRangePicker.md +89 -471
  20. package/dist/components/inputs/PercentageInput.md +183 -19
  21. package/dist/components/inputs/RadioButton.md +163 -35
  22. package/dist/components/inputs/RadioList.md +241 -0
  23. package/dist/components/inputs/RadioTileGroup.md +146 -62
  24. package/dist/components/inputs/Select.md +219 -328
  25. package/dist/components/inputs/Slider.md +334 -0
  26. package/dist/components/inputs/Switch.md +136 -376
  27. package/dist/components/inputs/Textarea.md +209 -11
  28. package/dist/components/inputs/Uploader/Uploader.md +145 -66
  29. package/dist/components/inputs/llms.txt +3 -0
  30. package/dist/components/navigation/Breadcrumbs.md +80 -322
  31. package/dist/components/navigation/Dropdown.md +92 -221
  32. package/dist/components/navigation/IconMenuButton.md +40 -502
  33. package/dist/components/navigation/InsetDrawer.md +68 -738
  34. package/dist/components/navigation/Link.md +39 -298
  35. package/dist/components/navigation/Menu.md +92 -285
  36. package/dist/components/navigation/MenuButton.md +55 -448
  37. package/dist/components/navigation/Pagination.md +47 -338
  38. package/dist/components/navigation/ProfileMenu.md +45 -268
  39. package/dist/components/navigation/Stepper.md +160 -28
  40. package/dist/components/navigation/Tabs.md +57 -316
  41. package/dist/components/surfaces/Sheet.md +150 -333
  42. package/dist/guides/ThemeProvider.md +116 -0
  43. package/dist/guides/llms.txt +9 -0
  44. package/dist/llms.txt +8 -0
  45. package/package.json +1 -1
@@ -2,10 +2,11 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- > ๐Ÿ’ก **Form ๊ตฌ์„ฑ ์‹œ ๋‚ด์žฅ prop ์‚ฌ์šฉ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค**
5
+ PercentageInput is a specialized numeric input for entering percentage values. It automatically appends a `%` suffix, formats numbers with thousand separators, and supports min/max validation with built-in error states. Use it for any field where users need to enter a percentage, such as tax rates, discounts, or commission rates.
6
+
7
+ > **Tip: Use built-in form props**
6
8
  >
7
- > ์ด ์ปดํฌ๋„ŒํŠธ๋Š” `label`, `helperText` ๋“ฑ์˜ Form ์š”์†Œ๋ฅผ ์ž์ฒด์ ์œผ๋กœ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
8
- > Form์„ ๊ตฌ์„ฑํ•  ๋•Œ Typography๋กœ ๋ณ„๋„์˜ label์ด๋‚˜ helperText๋ฅผ ๋งŒ๋“œ๋Š” ๋Œ€์‹ , ์ปดํฌ๋„ŒํŠธ์˜ ๋‚ด์žฅ prop์„ ์‚ฌ์šฉํ•˜์„ธ์š”.
9
+ > This component supports `label` and `helperText` props directly. Use these instead of wrapping with FormControl + FormLabel + FormHelperText for simpler forms.
9
10
 
10
11
  ```tsx
11
12
  <PercentageInput placeholder="Enter a percentage" />
@@ -27,7 +28,29 @@
27
28
  | min | โ€” | โ€” |
28
29
  | max | โ€” | โ€” |
29
30
 
30
- ### Sizes
31
+ ## Usage
32
+
33
+ ```tsx
34
+ import { PercentageInput } from '@ceed/ads';
35
+
36
+ function MyComponent() {
37
+ const [rate, setRate] = React.useState(0);
38
+
39
+ return (
40
+ <PercentageInput
41
+ label="Tax Rate"
42
+ value={rate}
43
+ onChange={(e) => setRate(e.target.value)}
44
+ min={0}
45
+ max={100}
46
+ />
47
+ );
48
+ }
49
+ ```
50
+
51
+ ## Sizes
52
+
53
+ PercentageInput supports three sizes: `sm`, `md` (default), and `lg`.
31
54
 
32
55
  ```tsx
33
56
  <Stack gap={2}>
@@ -37,44 +60,45 @@
37
60
  </Stack>
38
61
  ```
39
62
 
40
- ### Disabled
63
+ ## Form Features
64
+
65
+ ### With Label
41
66
 
42
67
  ```tsx
43
68
  <PercentageInput
44
69
  placeholder="Enter a percentage"
45
- disabled
70
+ label="Percentage Input"
46
71
  />
47
72
  ```
48
73
 
49
- ### Error
50
-
51
74
  ```tsx
52
- <PercentageInput
53
- placeholder="Enter a percentage"
54
- error
55
- />
75
+ <PercentageInput label="Discount Rate" />
56
76
  ```
57
77
 
58
- ### WithLabel
78
+ ### With Helper Text
59
79
 
60
80
  ```tsx
61
81
  <PercentageInput
62
82
  placeholder="Enter a percentage"
63
83
  label="Percentage Input"
84
+ helperText="Please enter a percentage"
64
85
  />
65
86
  ```
66
87
 
67
- ### WithHelperText
88
+ ```tsx
89
+ <PercentageInput label="Commission" helperText="Enter the commission percentage." />
90
+ ```
91
+
92
+ ### Error State
68
93
 
69
94
  ```tsx
70
95
  <PercentageInput
71
96
  placeholder="Enter a percentage"
72
- label="Percentage Input"
73
- helperText="Please enter a percentage"
97
+ error
74
98
  />
75
99
  ```
76
100
 
77
- ### WithErrorText
101
+ ### With Error Text
78
102
 
79
103
  ```tsx
80
104
  <PercentageInput
@@ -96,7 +120,20 @@
96
120
  />
97
121
  ```
98
122
 
99
- ### Min
123
+ ### Disabled
124
+
125
+ ```tsx
126
+ <PercentageInput
127
+ placeholder="Enter a percentage"
128
+ disabled
129
+ />
130
+ ```
131
+
132
+ ## Min / Max Validation
133
+
134
+ Set `min` and `max` to enforce value boundaries. When the entered value is outside the range, the input automatically shows an error state.
135
+
136
+ ### Minimum Value
100
137
 
101
138
  ```tsx
102
139
  <PercentageInput
@@ -108,7 +145,12 @@
108
145
  />
109
146
  ```
110
147
 
111
- ### Max
148
+ ```tsx
149
+ <PercentageInput min={10} defaultValue={5} />
150
+ {/* Shows error because 5 < 10 */}
151
+ ```
152
+
153
+ ### Maximum Value
112
154
 
113
155
  ```tsx
114
156
  <PercentageInput
@@ -119,3 +161,125 @@
119
161
  defaultValue={5000}
120
162
  />
121
163
  ```
164
+
165
+ ```tsx
166
+ <PercentageInput max={500} defaultValue={5000} />
167
+ {/* Shows error because 5000 > 500 */}
168
+ ```
169
+
170
+ ## Decimal Scale
171
+
172
+ Use `maxDecimalScale` to control the number of decimal places allowed. The default is `0` (integers only).
173
+
174
+ ```tsx
175
+ // Integer only (default)
176
+ <PercentageInput maxDecimalScale={0} />
177
+
178
+ // Up to 2 decimal places: 12.34%
179
+ <PercentageInput maxDecimalScale={2} />
180
+
181
+ // Up to 3 decimal places: 12.345%
182
+ <PercentageInput maxDecimalScale={3} />
183
+ ```
184
+
185
+ ## Minor Unit Mode
186
+
187
+ When `useMinorUnit` is `true`, the component converts between display values and minor units based on `maxDecimalScale`. This is useful when your API stores percentages in integer form.
188
+
189
+ ```tsx
190
+ // Display shows "20.12%", onChange returns 20120
191
+ <PercentageInput useMinorUnit maxDecimalScale={3} value={20120} />
192
+
193
+ // Display shows "20.12%", onChange returns 20.12
194
+ <PercentageInput useMinorUnit={false} maxDecimalScale={2} value={20.12} />
195
+ ```
196
+
197
+ ## Common Use Cases
198
+
199
+ ### Discount Configuration
200
+
201
+ ```tsx
202
+ function DiscountSetting() {
203
+ const [discount, setDiscount] = React.useState(0);
204
+
205
+ return (
206
+ <PercentageInput
207
+ label="Discount"
208
+ helperText="Enter 0-100%"
209
+ value={discount}
210
+ onChange={(e) => setDiscount(e.target.value)}
211
+ min={0}
212
+ max={100}
213
+ />
214
+ );
215
+ }
216
+ ```
217
+
218
+ ### Tax Rate Settings
219
+
220
+ ```tsx
221
+ function TaxRateForm() {
222
+ return (
223
+ <Stack gap={2}>
224
+ <PercentageInput
225
+ label="VAT Rate"
226
+ defaultValue={10}
227
+ maxDecimalScale={2}
228
+ min={0}
229
+ max={100}
230
+ />
231
+ <PercentageInput
232
+ label="Local Tax Rate"
233
+ defaultValue={2.5}
234
+ maxDecimalScale={2}
235
+ min={0}
236
+ max={50}
237
+ />
238
+ </Stack>
239
+ );
240
+ }
241
+ ```
242
+
243
+ ### Progress / Completion Tracker
244
+
245
+ ```tsx
246
+ function CompletionTracker({ value, onChange }) {
247
+ return (
248
+ <PercentageInput
249
+ label="Completion"
250
+ value={value}
251
+ onChange={(e) => onChange(e.target.value)}
252
+ min={0}
253
+ max={100}
254
+ helperText={value >= 100 ? 'Task is complete!' : `${100 - value}% remaining`}
255
+ />
256
+ );
257
+ }
258
+ ```
259
+
260
+ ## Best Practices
261
+
262
+ 1. **Always set min and max**: Bound the valid range to prevent unreasonable values.
263
+
264
+ ```tsx
265
+ // โœ… Clear bounds
266
+ <PercentageInput min={0} max={100} />
267
+
268
+ // โŒ Unbounded โ€” user could enter 99999%
269
+ <PercentageInput />
270
+ ```
271
+
272
+ 2. **Use `maxDecimalScale` appropriately**: Set it to `0` for whole percentages (discounts, progress), or `2`โ€“`3` for precise rates (tax, interest).
273
+
274
+ 3. **Use `useMinorUnit` for API compatibility**: When your backend stores percentages as integers (e.g., 1050 for 10.50%), enable `useMinorUnit` with the appropriate `maxDecimalScale`.
275
+
276
+ 4. **Provide context via labels and helper text**: Clarify what the percentage represents and what range is valid.
277
+
278
+ 5. **Handle edge cases**: Consider what happens at boundary values (0%, 100%) and negative percentages if allowed.
279
+
280
+ ## Accessibility
281
+
282
+ - The input has proper labeling via the `label` prop, linked with `aria-labelledby`.
283
+ - Error states trigger `aria-invalid` with associated error messages via `aria-describedby`.
284
+ - The `%` suffix is a visual decoration โ€” ensure labels clarify that the field expects a percentage for screen readers.
285
+ - Min/max validation errors are communicated visually; add descriptive `helperText` to make the valid range clear.
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- Radio ์ปดํฌ๋„ŒํŠธ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ์˜ต์…˜ ์ค‘ ํ•˜๋‚˜๋งŒ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋Š” ๋‹จ์ผ ์„ ํƒ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ๋ผ๋””์˜ค ๋ฒ„ํŠผ์€ ๊ทธ๋ฃน์œผ๋กœ ์‚ฌ์šฉ๋˜์–ด์•ผ ํ•˜๋ฉฐ, ํ•˜๋‚˜๊ฐ€ ์„ ํƒ๋˜๋ฉด ๋‹ค๋ฅธ ์˜ต์…˜๋“ค์€ ์ž๋™์œผ๋กœ ํ•ด์ œ๋ฉ๋‹ˆ๋‹ค.
5
+ The Radio component provides a single-selection interface where users can choose exactly one option from a set of mutually exclusive choices. When one radio button is selected, any previously selected option in the same group is automatically deselected.
6
+
7
+ Radio buttons are built on Joy UI's Radio and RadioGroup components, supporting multiple visual variants, sizes, colors, and advanced customization such as custom icons, overlay interactions, and icon-free designs. They are ideal for settings forms, preference panels, and any UI where a user must commit to a single option from a predefined list.
6
8
 
7
9
  ```tsx
8
10
  <Radio />
@@ -28,35 +30,28 @@ Radio ์ปดํฌ๋„ŒํŠธ๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์—ฌ๋Ÿฌ ์˜ต์…˜ ์ค‘ ํ•˜๋‚˜๋งŒ ์„ ํƒํ•  ์ˆ˜ ์žˆ
28
30
  ## Usage
29
31
 
30
32
  ```tsx
31
- import { Radio } from '@ceed/ads';
33
+ import { Radio, RadioGroup } from '@ceed/ads';
32
34
 
33
35
  function MyComponent() {
34
36
  const [selectedValue, setSelectedValue] = useState('option1');
35
37
 
36
38
  return (
37
- <div>
38
- <Radio
39
- name="example"
40
- value="option1"
41
- checked={selectedValue === 'option1'}
42
- onChange={(e) => setSelectedValue(e.target.value)}
43
- label="์˜ต์…˜ 1"
44
- />
45
- <Radio
46
- name="example"
47
- value="option2"
48
- checked={selectedValue === 'option2'}
49
- onChange={(e) => setSelectedValue(e.target.value)}
50
- label="์˜ต์…˜ 2"
51
- />
52
- </div>
39
+ <RadioGroup
40
+ name="example"
41
+ value={selectedValue}
42
+ onChange={(e) => setSelectedValue(e.target.value)}
43
+ >
44
+ <Radio value="option1" label="Option 1" />
45
+ <Radio value="option2" label="Option 2" />
46
+ <Radio value="option3" label="Option 3" />
47
+ </RadioGroup>
53
48
  );
54
49
  }
55
50
  ```
56
51
 
57
- ## Examples
52
+ ## Variants
58
53
 
59
- ### Variants
54
+ Radio supports four visual variants: `outlined` (default), `soft`, `solid`, and `plain`. Choose a variant that fits the visual context of your form.
60
55
 
61
56
  ```tsx
62
57
  <FormControl>
@@ -70,7 +65,9 @@ function MyComponent() {
70
65
  </FormControl>
71
66
  ```
72
67
 
73
- ### Sizes
68
+ ## Sizes
69
+
70
+ Three size presets are available: `sm`, `md` (default), and `lg`. Use smaller sizes for compact layouts and larger sizes for touch-friendly interfaces.
74
71
 
75
72
  ```tsx
76
73
  <FormControl>
@@ -83,7 +80,9 @@ function MyComponent() {
83
80
  </FormControl>
84
81
  ```
85
82
 
86
- ### Colors
83
+ ## Colors
84
+
85
+ Radio supports five semantic colors: `primary`, `neutral`, `danger`, `success`, and `warning`. Use semantic colors to convey meaning -- for example, `danger` for destructive options or `success` for confirmed selections.
87
86
 
88
87
  ```tsx
89
88
  <FormControl>
@@ -98,9 +97,9 @@ function MyComponent() {
98
97
  </FormControl>
99
98
  ```
100
99
 
101
- ### Custom Icons
100
+ ## Custom Icons
102
101
 
103
- ์•„์ด์ฝ˜์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•˜์—ฌ ํŠน๋ณ„ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
102
+ Replace the default radio indicator with custom icons using the `checkedIcon` prop. This is useful for card-style selectors where the selection state needs a distinctive visual treatment.
104
103
 
105
104
  ```tsx
106
105
  <RadioGroup aria-label="platform" defaultValue="Website" overlay name="platform" sx={{
@@ -142,9 +141,9 @@ function MyComponent() {
142
141
  </RadioGroup>
143
142
  ```
144
143
 
145
- ### No Icon
144
+ ## No Icon
146
145
 
147
- ์•„์ด์ฝ˜ ์—†์ด ํ…์ŠคํŠธ๋งŒ์œผ๋กœ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
146
+ Use the `disableIcon` prop to hide the radio indicator entirely. This pattern is commonly used for card-style selectors where the entire card acts as the selectable target, and the selection state is conveyed through border or background styling.
148
147
 
149
148
  ```tsx
150
149
  <Box sx={{
@@ -195,9 +194,9 @@ Storage
195
194
  </Box>
196
195
  ```
197
196
 
198
- ### Segmented Controls
197
+ ## Segmented Controls
199
198
 
200
- ์„ธ๊ทธ๋จผํŠธ ์ปจํŠธ๋กค ์Šคํƒ€์ผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
199
+ Radio buttons can be styled as segmented controls for compact, inline option switching. This pattern works well for toolbar-style controls where horizontal space is limited.
201
200
 
202
201
  ```tsx
203
202
  <Box sx={{
@@ -238,9 +237,9 @@ Storage
238
237
  </Box>
239
238
  ```
240
239
 
241
- ### Product Attributes
240
+ ## Product Attributes
242
241
 
243
- ์ œํ’ˆ ์†์„ฑ ์„ ํƒ ๋“ฑ์˜ ์šฉ๋„๋กœ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
242
+ Radio groups can be customized to represent product attributes such as colors and sizes. Using `overlay`, `disableIcon`, and custom `Sheet` containers, you can create rich visual selectors.
244
243
 
245
244
  ```tsx
246
245
  <Box sx={{
@@ -337,14 +336,143 @@ Size
337
336
  </Box>
338
337
  ```
339
338
 
339
+ ## Common Use Cases
340
+
341
+ ### Survey / Questionnaire Form
342
+
343
+ ```tsx
344
+ function SurveyQuestion() {
345
+ const [answer, setAnswer] = useState('');
346
+
347
+ return (
348
+ <FormControl>
349
+ <FormLabel>How satisfied are you with our service?</FormLabel>
350
+ <RadioGroup
351
+ name="satisfaction"
352
+ value={answer}
353
+ onChange={(e) => setAnswer(e.target.value)}
354
+ >
355
+ <Radio value="very-satisfied" label="Very Satisfied" color="success" />
356
+ <Radio value="satisfied" label="Satisfied" />
357
+ <Radio value="neutral" label="Neutral" />
358
+ <Radio value="dissatisfied" label="Dissatisfied" color="warning" />
359
+ <Radio value="very-dissatisfied" label="Very Dissatisfied" color="danger" />
360
+ </RadioGroup>
361
+ </FormControl>
362
+ );
363
+ }
364
+ ```
365
+
366
+ ### Payment Method Selection
367
+
368
+ ```tsx
369
+ function PaymentMethodSelector() {
370
+ const [method, setMethod] = useState('credit-card');
371
+
372
+ return (
373
+ <FormControl>
374
+ <FormLabel>Payment Method</FormLabel>
375
+ <RadioGroup
376
+ name="payment"
377
+ value={method}
378
+ onChange={(e) => setMethod(e.target.value)}
379
+ sx={{ gap: 1.5 }}
380
+ >
381
+ {[
382
+ { value: 'credit-card', label: 'Credit Card' },
383
+ { value: 'bank-transfer', label: 'Bank Transfer' },
384
+ { value: 'paypal', label: 'PayPal' },
385
+ ].map((option) => (
386
+ <Sheet key={option.value} variant="outlined" sx={{ p: 2, borderRadius: 'md' }}>
387
+ <Radio
388
+ overlay
389
+ value={option.value}
390
+ label={option.label}
391
+ slotProps={{
392
+ action: ({ checked }) => ({
393
+ sx: {
394
+ ...(checked && {
395
+ '--variant-borderWidth': '2px',
396
+ borderColor: 'primary.500',
397
+ }),
398
+ },
399
+ }),
400
+ }}
401
+ />
402
+ </Sheet>
403
+ ))}
404
+ </RadioGroup>
405
+ </FormControl>
406
+ );
407
+ }
408
+ ```
409
+
410
+ ### Shipping Speed Selection
411
+
412
+ ```tsx
413
+ function ShippingOptions() {
414
+ const [shipping, setShipping] = useState('standard');
415
+
416
+ return (
417
+ <FormControl>
418
+ <FormLabel>Shipping Speed</FormLabel>
419
+ <RadioGroup
420
+ name="shipping"
421
+ value={shipping}
422
+ onChange={(e) => setShipping(e.target.value)}
423
+ >
424
+ <Radio value="standard" label="Standard (5-7 business days) - Free" />
425
+ <Radio value="express" label="Express (2-3 business days) - $9.99" />
426
+ <Radio value="overnight" label="Overnight (next day) - $24.99" />
427
+ </RadioGroup>
428
+ </FormControl>
429
+ );
430
+ }
431
+ ```
432
+
340
433
  ## Best Practices
341
434
 
342
- 1. **๊ทธ๋ฃน ์‚ฌ์šฉ**: Radio ๋ฒ„ํŠผ๋“ค์€ ๋ฐ˜๋“œ์‹œ ๋™์ผํ•œ `name` ์†์„ฑ์„ ๊ฐ€์ง„ ๊ทธ๋ฃน์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
435
+ 1. **Always use RadioGroup**: Wrap Radio buttons in a `RadioGroup` to ensure proper grouping, keyboard navigation, and mutual exclusivity.
436
+
437
+ ```tsx
438
+ // โœ… Wrapped in RadioGroup
439
+ <RadioGroup name="options" value={value} onChange={handleChange}>
440
+ <Radio value="a" label="Option A" />
441
+ <Radio value="b" label="Option B" />
442
+ </RadioGroup>
443
+
444
+ // โŒ Standalone radios without a group
445
+ <Radio name="options" value="a" label="Option A" />
446
+ <Radio name="options" value="b" label="Option B" />
447
+ ```
448
+
449
+ 2. **Provide clear labels**: Every radio button must have a visible label or an `aria-label` to describe its purpose.
450
+
451
+ ```tsx
452
+ // โœ… Descriptive label
453
+ <Radio value="monthly" label="Monthly billing ($10/month)" />
454
+
455
+ // โŒ Vague label
456
+ <Radio value="monthly" label="Option 1" />
457
+ ```
458
+
459
+ 3. **Set a default selection**: Pre-select the most common or recommended option using `defaultValue` or a controlled `value` to reduce user effort.
460
+
461
+ ```tsx
462
+ // โœ… Sensible default
463
+ <RadioGroup defaultValue="standard" name="shipping">
464
+ <Radio value="standard" label="Standard Shipping" />
465
+ <Radio value="express" label="Express Shipping" />
466
+ </RadioGroup>
467
+ ```
343
468
 
344
- 2. **๋ ˆ์ด๋ธ” ์ œ๊ณต**: ์ ‘๊ทผ์„ฑ์„ ์œ„ํ•ด ํ•ญ์ƒ ์˜๋ฏธ ์žˆ๋Š” `label`์„ ์ œ๊ณตํ•˜์„ธ์š”.
469
+ 4. **Limit options to 2-7 items**: If more than 7 options exist, consider using a Select or Autocomplete component instead.
345
470
 
346
- 3. **์ดˆ๊ธฐ๊ฐ’ ์„ค์ •**: ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ์œ„ํ•ด ์ ์ ˆํ•œ ์ดˆ๊ธฐ๊ฐ’์„ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
471
+ 5. **Use vertical layout by default**: Vertical lists are easier to scan. Only use horizontal (`orientation="horizontal"`) when options are very short (e.g., segmented controls).
347
472
 
348
- 4. **์ ์ ˆํ•œ ๊ฐ„๊ฒฉ**: ์—ฌ๋Ÿฌ ๋ผ๋””์˜ค ๋ฒ„ํŠผ ๊ฐ„์—๋Š” ์ถฉ๋ถ„ํ•œ ๊ฐ„๊ฒฉ์„ ๋‘์–ด ์„ ํƒํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“œ์„ธ์š”.
473
+ ## Accessibility
349
474
 
350
- 5. **์ƒํƒœ ๊ด€๋ฆฌ**: ์ œ์–ด ์ปดํฌ๋„ŒํŠธ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ์ƒํƒœ๋ฅผ ๋ช…ํ™•ํžˆ ๊ด€๋ฆฌํ•˜์„ธ์š”.
475
+ - **Keyboard navigation**: Users can move between options using `Arrow Up` / `Arrow Down` (vertical) or `Arrow Left` / `Arrow Right` (horizontal). `Space` selects the focused option.
476
+ - **ARIA roles**: `RadioGroup` renders with `role="radiogroup"`, and each `Radio` renders with `role="radio"` and `aria-checked` reflecting its state.
477
+ - **Labeling**: Always connect a `FormLabel` to the `RadioGroup` via `aria-labelledby`, or provide an `aria-label` directly on the group so screen readers can announce the group purpose.
478
+ - **Focus management**: When using `overlay` or `disableIcon` patterns, ensure the interactive area is clearly communicated -- the `overlay` prop extends the clickable area to the parent container, which is also reflected in focus styling.