@ceed/ads 1.35.1 → 1.37.0
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.
- package/README.md +85 -95
- package/dist/components/Accordions/Accordions.d.ts +1 -0
- package/dist/components/Alert/Alert.d.ts +5 -5
- package/dist/components/Autocomplete/Autocomplete.d.ts +2 -2
- package/dist/components/Avatar/Avatar.d.ts +7 -17
- package/dist/components/Box/Box.d.ts +1 -0
- package/dist/components/Breadcrumbs/Breadcrumbs.d.ts +6 -5
- package/dist/components/Button/Button.d.ts +3 -2
- package/dist/components/Calendar/Calendar.d.ts +1 -0
- package/dist/components/Card/Card.d.ts +1 -0
- package/dist/components/Checkbox/Checkbox.d.ts +1 -0
- package/dist/components/Chip/Chip.d.ts +1 -0
- package/dist/components/Container/Container.d.ts +6 -1
- package/dist/components/DialogActions/DialogActions.d.ts +1 -0
- package/dist/components/DialogContent/DialogContent.d.ts +1 -0
- package/dist/components/DialogFrame/DialogFrame.d.ts +1 -1
- package/dist/components/DialogTitle/DialogTitle.d.ts +1 -0
- package/dist/components/Divider/Divider.d.ts +1 -0
- package/dist/components/Dropdown/Dropdown.d.ts +28 -1
- package/dist/components/FilterMenu/components/MonthRange.d.ts +11 -0
- package/dist/components/FilterMenu/types.d.ts +5 -1
- package/dist/components/FormControl/FormControl.d.ts +1 -0
- package/dist/components/FormHelperText/FormHelperText.d.ts +1 -0
- package/dist/components/FormLabel/FormLabel.d.ts +1 -0
- package/dist/components/Grid/Grid.d.ts +1 -0
- package/dist/components/IconButton/IconButton.d.ts +3 -2
- package/dist/components/IconMenuButton/IconMenuButton.d.ts +7 -6
- package/dist/components/InfoSign/InfoSign.d.ts +3 -2
- package/dist/components/Input/Input.d.ts +8 -22
- package/dist/components/InsetDrawer/InsetDrawer.d.ts +1 -0
- package/dist/components/Markdown/Markdown.d.ts +9 -24
- package/dist/components/Menu/Menu.d.ts +2 -1
- package/dist/components/MenuButton/MenuButton.d.ts +10 -8
- package/dist/components/Modal/Modal.d.ts +4 -2
- package/dist/components/NavigationGroup/NavigationGroup.d.ts +3 -2
- package/dist/components/NavigationItem/NavigationItem.d.ts +3 -2
- package/dist/components/Navigator/Navigator.d.ts +5 -4
- package/dist/components/Pagination/Pagination.d.ts +1 -1
- package/dist/components/ProfileMenu/ProfileMenu.d.ts +2 -2
- package/dist/components/Radio/Radio.d.ts +1 -0
- package/dist/components/RadioList/RadioList.d.ts +3 -2
- package/dist/components/Select/Select.d.ts +20 -10
- package/dist/components/Sheet/Sheet.d.ts +1 -0
- package/dist/components/Stack/Stack.d.ts +1 -0
- package/dist/components/Stepper/Stepper.d.ts +2 -1
- package/dist/components/Switch/Switch.d.ts +1 -0
- package/dist/components/Table/Table.d.ts +7 -5
- package/dist/components/Tabs/Tabs.d.ts +1 -0
- package/dist/components/Textarea/Textarea.d.ts +8 -20
- package/dist/components/ThemeProvider/ThemeProvider.d.ts +4 -2
- package/dist/components/Tooltip/Tooltip.d.ts +1 -0
- package/dist/components/Typography/Typography.d.ts +1 -0
- package/dist/components/Uploader/Uploader.d.ts +18 -17
- package/dist/components/data-display/Avatar.md +60 -72
- package/dist/components/data-display/Badge.md +197 -181
- package/dist/components/data-display/Chip.md +164 -142
- package/dist/components/data-display/DataTable.md +843 -338
- package/dist/components/data-display/InfoSign.md +1 -3
- package/dist/components/data-display/Markdown.md +93 -125
- package/dist/components/data-display/Table.md +1453 -1007
- package/dist/components/data-display/Typography.md +101 -104
- package/dist/components/feedback/Alert.md +80 -86
- package/dist/components/feedback/CircularProgress.md +32 -36
- package/dist/components/feedback/Dialog.md +25 -17
- package/dist/components/feedback/Modal.md +296 -265
- package/dist/components/feedback/Skeleton.md +125 -89
- package/dist/components/index.d.ts +60 -1
- package/dist/components/inputs/Autocomplete.md +191 -95
- package/dist/components/inputs/Button.md +83 -83
- package/dist/components/inputs/ButtonGroup.md +195 -185
- package/dist/components/inputs/Calendar.md +25 -28
- package/dist/components/inputs/Checkbox.md +11 -29
- package/dist/components/inputs/CurrencyInput.md +4 -4
- package/dist/components/inputs/DatePicker.md +229 -110
- package/dist/components/inputs/DateRangePicker.md +248 -137
- package/dist/components/inputs/FilterMenu.md +138 -8
- package/dist/components/inputs/FilterableCheckboxGroup.md +115 -55
- package/dist/components/inputs/FormControl.md +75 -69
- package/dist/components/inputs/IconButton.md +229 -205
- package/dist/components/inputs/Input.md +131 -98
- package/dist/components/inputs/MonthPicker.md +186 -84
- package/dist/components/inputs/MonthRangePicker.md +73 -49
- package/dist/components/inputs/PercentageInput.md +15 -31
- package/dist/components/inputs/RadioButton.md +320 -256
- package/dist/components/inputs/RadioList.md +66 -50
- package/dist/components/inputs/RadioTileGroup.md +287 -170
- package/dist/components/inputs/SearchBar.md +82 -60
- package/dist/components/inputs/Select.md +181 -115
- package/dist/components/inputs/Slider.md +153 -102
- package/dist/components/inputs/Switch.md +193 -138
- package/dist/components/inputs/Textarea.md +15 -20
- package/dist/components/inputs/Uploader/Uploader.md +68 -39
- package/dist/components/layout/Box.md +841 -662
- package/dist/components/layout/Container.md +3 -11
- package/dist/components/layout/Grid.md +480 -394
- package/dist/components/layout/Stack.md +739 -566
- package/dist/components/navigation/Breadcrumbs.md +182 -116
- package/dist/components/navigation/Dropdown.md +732 -391
- package/dist/components/navigation/IconMenuButton.md +14 -6
- package/dist/components/navigation/InsetDrawer.md +550 -378
- package/dist/components/navigation/Link.md +104 -94
- package/dist/components/navigation/Menu.md +623 -502
- package/dist/components/navigation/MenuButton.md +18 -10
- package/dist/components/navigation/NavigationGroup.md +19 -50
- package/dist/components/navigation/NavigationItem.md +6 -6
- package/dist/components/navigation/Navigator.md +26 -28
- package/dist/components/navigation/Pagination.md +86 -75
- package/dist/components/navigation/ProfileMenu.md +65 -43
- package/dist/components/navigation/Stepper.md +2 -12
- package/dist/components/navigation/Tabs.md +209 -183
- package/dist/components/surfaces/Accordions.md +89 -172
- package/dist/components/surfaces/Card.md +1094 -709
- package/dist/components/surfaces/Divider.md +562 -412
- package/dist/components/surfaces/Sheet.md +700 -518
- package/dist/guides/ThemeProvider.md +65 -40
- package/dist/index.browser.js +4 -4
- package/dist/index.browser.js.map +4 -4
- package/dist/index.cjs +1655 -1548
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1314 -1199
- package/framer/index.js +1 -1
- package/package.json +32 -35
|
@@ -52,9 +52,9 @@ When the input has a value, hovering over the component reveals a clear (✕) bu
|
|
|
52
52
|
|
|
53
53
|
```tsx
|
|
54
54
|
<Stack alignItems="flex-start" gap={2}>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
</Stack>
|
|
55
|
+
<Typography level="body-sm">Hover over the input to reveal the clear (✕) button.</Typography>
|
|
56
|
+
<SearchBar value={value} onChange={setValue} />
|
|
57
|
+
</Stack>
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
## Placeholder
|
|
@@ -63,19 +63,25 @@ Each `SearchBarOption` can include a `placeholder` field that is shown in the te
|
|
|
63
63
|
|
|
64
64
|
```tsx
|
|
65
65
|
<Stack alignItems="flex-start" gap={3}>
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
67
|
+
<Typography level="body-xs" fontWeight="md">
|
|
68
|
+
No placeholder prop — uses the active option's placeholder
|
|
69
|
+
</Typography>
|
|
70
|
+
<SearchBar showSelect options={SAMPLE_OPTIONS} value={value} onChange={setValue} />
|
|
71
|
+
</Stack>
|
|
72
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
73
|
+
<Typography level="body-xs" fontWeight="md">
|
|
74
|
+
placeholder="Search by keyword" — overrides option-level placeholder
|
|
75
|
+
</Typography>
|
|
76
|
+
<SearchBar
|
|
77
|
+
showSelect
|
|
78
|
+
options={SAMPLE_OPTIONS}
|
|
79
|
+
placeholder="Search by keyword"
|
|
80
|
+
value={value}
|
|
81
|
+
onChange={setValue}
|
|
82
|
+
/>
|
|
83
|
+
</Stack>
|
|
71
84
|
</Stack>
|
|
72
|
-
<Stack alignItems="flex-start" gap={1}>
|
|
73
|
-
<Typography level="body-xs" fontWeight="md">
|
|
74
|
-
placeholder="Search by keyword" — overrides option-level placeholder
|
|
75
|
-
</Typography>
|
|
76
|
-
<SearchBar showSelect options={SAMPLE_OPTIONS} placeholder="Search by keyword" value={value} onChange={setValue} />
|
|
77
|
-
</Stack>
|
|
78
|
-
</Stack>
|
|
79
85
|
```
|
|
80
86
|
|
|
81
87
|
## onSearch
|
|
@@ -84,32 +90,46 @@ Each `SearchBarOption` can include a `placeholder` field that is shown in the te
|
|
|
84
90
|
|
|
85
91
|
```tsx
|
|
86
92
|
<Stack alignItems="flex-start" gap={2}>
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
<SearchBar
|
|
94
|
+
showSelect
|
|
95
|
+
options={SAMPLE_OPTIONS}
|
|
96
|
+
value={value}
|
|
97
|
+
onChange={setValue}
|
|
98
|
+
onSearch={setLastSearch}
|
|
99
|
+
/>
|
|
100
|
+
<Typography level="body-sm">value: "{value}"</Typography>
|
|
101
|
+
{lastSearch && (
|
|
102
|
+
<Typography level="body-sm">
|
|
103
|
+
onSearch: [{lastSearch.selectValue}] "{lastSearch.inputValue}"
|
|
104
|
+
</Typography>
|
|
105
|
+
)}
|
|
106
|
+
</Stack>
|
|
93
107
|
```
|
|
94
108
|
|
|
95
109
|
When `showSelect` is `false`, `selectValue` is omitted from the payload entirely — not `undefined` as a key, but absent.
|
|
96
110
|
|
|
97
111
|
```tsx
|
|
98
112
|
<Stack alignItems="flex-start" gap={2}>
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
+
<Typography level="body-sm">
|
|
114
|
+
When <code>showSelect</code> is <code>false</code>, <code>selectValue</code> is omitted from
|
|
115
|
+
the <code>onSearch</code> payload.
|
|
116
|
+
</Typography>
|
|
117
|
+
<SearchBar value={value} onChange={setValue} onSearch={setLastSearch} />
|
|
118
|
+
{lastSearch && (
|
|
119
|
+
<Stack alignItems="flex-start" gap={0.5}>
|
|
120
|
+
<Typography level="body-sm">inputValue: "{lastSearch.inputValue}"</Typography>
|
|
121
|
+
<Typography
|
|
122
|
+
level="body-sm"
|
|
123
|
+
sx={{
|
|
124
|
+
color: lastSearch.selectValue === undefined ? "success.500" : "danger.500"
|
|
125
|
+
}}
|
|
126
|
+
>
|
|
127
|
+
selectValue:{" "}
|
|
128
|
+
{lastSearch.selectValue === undefined ? "undefined ✅" : `"${lastSearch.selectValue}" ❌`}
|
|
129
|
+
</Typography>
|
|
130
|
+
</Stack>
|
|
131
|
+
)}
|
|
132
|
+
</Stack>
|
|
113
133
|
```
|
|
114
134
|
|
|
115
135
|
## Width
|
|
@@ -118,31 +138,33 @@ SearchBar sizes to its content by default. Pass any `Box` width prop to constrai
|
|
|
118
138
|
|
|
119
139
|
```tsx
|
|
120
140
|
<Stack alignItems="flex-start" gap={3}>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
</
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
</
|
|
145
|
-
|
|
141
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
142
|
+
<Typography level="body-xs" fontWeight="md">
|
|
143
|
+
width="100%" — stretches to parent width
|
|
144
|
+
</Typography>
|
|
145
|
+
<Box
|
|
146
|
+
sx={{
|
|
147
|
+
border: "1px dashed",
|
|
148
|
+
borderColor: "neutral.300",
|
|
149
|
+
padding: 1
|
|
150
|
+
}}
|
|
151
|
+
>
|
|
152
|
+
<SearchBar width="100%" value={value} onChange={setValue} />
|
|
153
|
+
</Box>
|
|
154
|
+
</Stack>
|
|
155
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
156
|
+
<Typography level="body-xs" fontWeight="md">
|
|
157
|
+
width={400} — fixed 400px
|
|
158
|
+
</Typography>
|
|
159
|
+
<SearchBar width={400} value={value} onChange={setValue} />
|
|
160
|
+
</Stack>
|
|
161
|
+
<Stack alignItems="flex-start" gap={1}>
|
|
162
|
+
<Typography level="body-xs" fontWeight="md">
|
|
163
|
+
No width prop — sizes to content (inline-flex default)
|
|
164
|
+
</Typography>
|
|
165
|
+
<SearchBar value={value} onChange={setValue} />
|
|
166
|
+
</Stack>
|
|
167
|
+
</Stack>
|
|
146
168
|
```
|
|
147
169
|
|
|
148
170
|
## Props and Customization
|
|
@@ -54,13 +54,7 @@ const options = [
|
|
|
54
54
|
];
|
|
55
55
|
|
|
56
56
|
function MyComponent() {
|
|
57
|
-
return
|
|
58
|
-
<Select
|
|
59
|
-
label="Choose a pet"
|
|
60
|
-
options={options}
|
|
61
|
-
defaultValue="dog"
|
|
62
|
-
/>
|
|
63
|
-
);
|
|
57
|
+
return <Select label="Choose a pet" options={options} defaultValue="dog" />;
|
|
64
58
|
}
|
|
65
59
|
```
|
|
66
60
|
|
|
@@ -70,11 +64,11 @@ Select supports four visual styles: `outlined` (default), `plain`, `soft`, and `
|
|
|
70
64
|
|
|
71
65
|
```tsx
|
|
72
66
|
<Stack spacing={4}>
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
</Stack>
|
|
67
|
+
<Select defaultValue="dog" options={options} />
|
|
68
|
+
<Select defaultValue="dog" variant="plain" options={options} />
|
|
69
|
+
<Select defaultValue="dog" variant="soft" options={options} />
|
|
70
|
+
<Select defaultValue="dog" variant="solid" options={options} />
|
|
71
|
+
</Stack>
|
|
78
72
|
```
|
|
79
73
|
|
|
80
74
|
```tsx
|
|
@@ -90,10 +84,10 @@ Three sizes are available: `sm`, `md` (default), and `lg`.
|
|
|
90
84
|
|
|
91
85
|
```tsx
|
|
92
86
|
<Stack spacing={4}>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
</Stack>
|
|
87
|
+
<Select defaultValue="dog" size="sm" options={options} />
|
|
88
|
+
<Select defaultValue="dog" size="md" options={options} />
|
|
89
|
+
<Select defaultValue="dog" size="lg" options={options} />
|
|
90
|
+
</Stack>
|
|
97
91
|
```
|
|
98
92
|
|
|
99
93
|
```tsx
|
|
@@ -108,12 +102,12 @@ Apply semantic colors to communicate intent or state.
|
|
|
108
102
|
|
|
109
103
|
```tsx
|
|
110
104
|
<Stack spacing={4}>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
</Stack>
|
|
105
|
+
<Select defaultValue="dog" color="primary" options={options} />
|
|
106
|
+
<Select defaultValue="dog" color="neutral" options={options} />
|
|
107
|
+
<Select defaultValue="dog" color="success" options={options} />
|
|
108
|
+
<Select defaultValue="dog" color="danger" options={options} />
|
|
109
|
+
<Select defaultValue="dog" color="warning" options={options} />
|
|
110
|
+
</Stack>
|
|
117
111
|
```
|
|
118
112
|
|
|
119
113
|
```tsx
|
|
@@ -129,11 +123,19 @@ Apply semantic colors to communicate intent or state.
|
|
|
129
123
|
Use `startDecorator` and `endDecorator` to add icons, badges, or other elements beside the select trigger.
|
|
130
124
|
|
|
131
125
|
```tsx
|
|
132
|
-
<Select
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
126
|
+
<Select
|
|
127
|
+
placeholder="Select a pet…"
|
|
128
|
+
startDecorator={<FavoriteBorder />}
|
|
129
|
+
endDecorator={
|
|
130
|
+
<Chip size="sm" color="danger" variant="soft">
|
|
131
|
+
+5
|
|
132
|
+
</Chip>
|
|
133
|
+
}
|
|
134
|
+
sx={{
|
|
135
|
+
width: 240
|
|
136
|
+
}}
|
|
137
|
+
options={options}
|
|
138
|
+
/>
|
|
137
139
|
```
|
|
138
140
|
|
|
139
141
|
```tsx
|
|
@@ -144,11 +146,13 @@ import { Chip } from '@ceed/ads';
|
|
|
144
146
|
placeholder="Select a pet..."
|
|
145
147
|
startDecorator={<FavoriteBorder />}
|
|
146
148
|
endDecorator={
|
|
147
|
-
<Chip size="sm" color="danger" variant="soft"
|
|
149
|
+
<Chip size="sm" color="danger" variant="soft">
|
|
150
|
+
+5
|
|
151
|
+
</Chip>
|
|
148
152
|
}
|
|
149
153
|
options={options}
|
|
150
154
|
sx={{ width: 240 }}
|
|
151
|
-
|
|
155
|
+
/>;
|
|
152
156
|
```
|
|
153
157
|
|
|
154
158
|
## Label and Helper Text
|
|
@@ -157,14 +161,14 @@ The `label` prop renders a form label above the select. The `helperText` prop re
|
|
|
157
161
|
|
|
158
162
|
```tsx
|
|
159
163
|
<>
|
|
160
|
-
|
|
161
|
-
</>
|
|
164
|
+
<Select label="Label" defaultValue="dog" options={options} />
|
|
165
|
+
</>
|
|
162
166
|
```
|
|
163
167
|
|
|
164
168
|
```tsx
|
|
165
169
|
<>
|
|
166
|
-
|
|
167
|
-
</>
|
|
170
|
+
<Select label="Select" helperText="I'm helper text" defaultValue="dog" options={options} />
|
|
171
|
+
</>
|
|
168
172
|
```
|
|
169
173
|
|
|
170
174
|
```tsx
|
|
@@ -184,17 +188,12 @@ Set `error` to `true` to visually indicate a validation error. Combine with `hel
|
|
|
184
188
|
|
|
185
189
|
```tsx
|
|
186
190
|
<>
|
|
187
|
-
|
|
188
|
-
</>
|
|
191
|
+
<Select label="label" error defaultValue="dog" options={options} />
|
|
192
|
+
</>
|
|
189
193
|
```
|
|
190
194
|
|
|
191
195
|
```tsx
|
|
192
|
-
<Select
|
|
193
|
-
label="Pet"
|
|
194
|
-
error
|
|
195
|
-
helperText="This field is required"
|
|
196
|
-
options={options}
|
|
197
|
-
/>
|
|
196
|
+
<Select label="Pet" error helperText="This field is required" options={options} />
|
|
198
197
|
```
|
|
199
198
|
|
|
200
199
|
## Form Control
|
|
@@ -203,9 +202,61 @@ Combining `label`, `helperText`, and `error` produces a complete form field. Her
|
|
|
203
202
|
|
|
204
203
|
```tsx
|
|
205
204
|
<>
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
</>
|
|
205
|
+
<Select label="Label" helperText="I'm helper text" defaultValue="dog" options={options} />
|
|
206
|
+
<Select label="Label" helperText="I'm helper text" defaultValue="dog" error options={options} />
|
|
207
|
+
</>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## Slot Props and Deterministic Ids
|
|
211
|
+
|
|
212
|
+
The `slotProps` prop targets both Joy Select's own slots (`button`, `listbox`, `root`, …) and the wrapper slots that `Select` composes around it (`formControl`, `formLabel`, `formHelperText`). Pass `id` (or `slotProps.formControl.id`) to pin the field's ids deterministically — `FormControl` derives the button `id` and the label `id` (`${id}-label`) from it, which keeps `byLabelText` / `byRole('combobox', { name })` queries stable in tests.
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<Stack
|
|
216
|
+
spacing={3}
|
|
217
|
+
sx={{
|
|
218
|
+
minWidth: 240
|
|
219
|
+
}}
|
|
220
|
+
>
|
|
221
|
+
{/* id seeds deterministic FormControl ids: button#pet, label#pet-label (testable via byLabelText/byRole) */}
|
|
222
|
+
<Select
|
|
223
|
+
id="pet"
|
|
224
|
+
label="Pet"
|
|
225
|
+
defaultValue="cat"
|
|
226
|
+
options={options}
|
|
227
|
+
slotProps={{
|
|
228
|
+
formLabel: {
|
|
229
|
+
sx: {
|
|
230
|
+
color: "primary.500"
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
formHelperText: {
|
|
234
|
+
sx: {
|
|
235
|
+
fontStyle: "italic"
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
button: {
|
|
239
|
+
"aria-describedby": "pet-extra"
|
|
240
|
+
}
|
|
241
|
+
}}
|
|
242
|
+
helperText="Wired via slotProps"
|
|
243
|
+
/>
|
|
244
|
+
</Stack>
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
<Select
|
|
249
|
+
id="pet"
|
|
250
|
+
label="Pet"
|
|
251
|
+
helperText="Wired via slotProps"
|
|
252
|
+
options={options}
|
|
253
|
+
slotProps={{
|
|
254
|
+
formLabel: { sx: { color: 'primary.500' } },
|
|
255
|
+
formHelperText: { sx: { fontStyle: 'italic' } },
|
|
256
|
+
button: { 'aria-describedby': 'pet-extra' },
|
|
257
|
+
}}
|
|
258
|
+
/>
|
|
259
|
+
// → renders button#pet and label#pet-label, connected via aria-labelledby
|
|
209
260
|
```
|
|
210
261
|
|
|
211
262
|
## Required Field
|
|
@@ -222,12 +273,7 @@ Set `required` to mark the field as required. An asterisk is added to the label
|
|
|
222
273
|
```
|
|
223
274
|
|
|
224
275
|
```tsx
|
|
225
|
-
<Select
|
|
226
|
-
label="Pet"
|
|
227
|
-
helperText="This field is required"
|
|
228
|
-
required
|
|
229
|
-
options={options}
|
|
230
|
-
/>
|
|
276
|
+
<Select label="Pet" helperText="This field is required" required options={options} />
|
|
231
277
|
```
|
|
232
278
|
|
|
233
279
|
## Multiple Selection
|
|
@@ -245,12 +291,7 @@ Set `multiple` to allow selecting more than one option. The value becomes an arr
|
|
|
245
291
|
```
|
|
246
292
|
|
|
247
293
|
```tsx
|
|
248
|
-
<Select
|
|
249
|
-
label="Pets"
|
|
250
|
-
multiple
|
|
251
|
-
defaultValue={['dog']}
|
|
252
|
-
options={options}
|
|
253
|
-
/>
|
|
294
|
+
<Select label="Pets" multiple defaultValue={['dog']} options={options} />
|
|
254
295
|
```
|
|
255
296
|
|
|
256
297
|
## Controlled Select
|
|
@@ -259,30 +300,41 @@ Use the `value` and `onChange` props for controlled behavior when you need to sy
|
|
|
259
300
|
|
|
260
301
|
```tsx
|
|
261
302
|
<div>
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
303
|
+
<Select
|
|
304
|
+
{...args}
|
|
305
|
+
options={options}
|
|
306
|
+
value={value}
|
|
307
|
+
onChange={(event, newValue) => {
|
|
308
|
+
setValue(newValue);
|
|
309
|
+
args.onChange?.(event, newValue);
|
|
310
|
+
}}
|
|
311
|
+
/>
|
|
312
|
+
<Select
|
|
313
|
+
{...args}
|
|
314
|
+
options={["dog", "cat", "fish", "bird"] as string[]}
|
|
315
|
+
value={value}
|
|
316
|
+
onChange={(event, newValue) => {
|
|
317
|
+
setValue(newValue);
|
|
318
|
+
args.onChange?.(event, newValue);
|
|
319
|
+
}}
|
|
320
|
+
/>
|
|
321
|
+
<Select
|
|
322
|
+
{...args}
|
|
323
|
+
options={["dog", "cat", "fish", "bird"] as string[]}
|
|
324
|
+
value={[value]}
|
|
325
|
+
onChange={(event, newValue) => {
|
|
326
|
+
setValue(newValue);
|
|
327
|
+
args.onChange?.(event, newValue);
|
|
328
|
+
}}
|
|
329
|
+
multiple
|
|
330
|
+
/>
|
|
331
|
+
</div>
|
|
275
332
|
```
|
|
276
333
|
|
|
277
334
|
```tsx
|
|
278
335
|
const [value, setValue] = useState('dog');
|
|
279
336
|
|
|
280
|
-
<Select
|
|
281
|
-
label="Pet"
|
|
282
|
-
value={value}
|
|
283
|
-
onChange={(event, newValue) => setValue(newValue)}
|
|
284
|
-
options={options}
|
|
285
|
-
/>
|
|
337
|
+
<Select label="Pet" value={value} onChange={(event, newValue) => setValue(newValue)} options={options} />;
|
|
286
338
|
```
|
|
287
339
|
|
|
288
340
|
## Disabled Options
|
|
@@ -308,7 +360,7 @@ const options = [
|
|
|
308
360
|
{ value: 'bird', label: 'Bird' },
|
|
309
361
|
];
|
|
310
362
|
|
|
311
|
-
<Select label="Pet" options={options} defaultValue="dog"
|
|
363
|
+
<Select label="Pet" options={options} defaultValue="dog" />;
|
|
312
364
|
```
|
|
313
365
|
|
|
314
366
|
## Options with Secondary Text
|
|
@@ -317,16 +369,27 @@ Add a `secondaryText` field to display supplementary information below each opti
|
|
|
317
369
|
|
|
318
370
|
```tsx
|
|
319
371
|
<Stack spacing={4} direction="row" alignItems="flex-start">
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
</
|
|
372
|
+
{sizes.map((size) => (
|
|
373
|
+
<Stack key={size} spacing={1}>
|
|
374
|
+
<span
|
|
375
|
+
style={{
|
|
376
|
+
color: "#6366f1",
|
|
377
|
+
fontSize: 12
|
|
378
|
+
}}
|
|
379
|
+
>
|
|
380
|
+
{size}
|
|
381
|
+
</span>
|
|
382
|
+
<Select
|
|
383
|
+
placeholder="Placeholder"
|
|
384
|
+
options={optionsWithSecondaryText}
|
|
385
|
+
sx={{
|
|
386
|
+
minWidth: 200
|
|
387
|
+
}}
|
|
388
|
+
size={size}
|
|
389
|
+
/>
|
|
390
|
+
</Stack>
|
|
391
|
+
))}
|
|
392
|
+
</Stack>
|
|
330
393
|
```
|
|
331
394
|
|
|
332
395
|
```tsx
|
|
@@ -336,7 +399,7 @@ const userOptions = [
|
|
|
336
399
|
{ value: 'sophia', label: 'Sophia Martinez', secondaryText: '(646) 555-0734' },
|
|
337
400
|
];
|
|
338
401
|
|
|
339
|
-
<Select placeholder="Select a contact" options={userOptions}
|
|
402
|
+
<Select placeholder="Select a contact" options={userOptions} />;
|
|
340
403
|
```
|
|
341
404
|
|
|
342
405
|
## Numeric Values
|
|
@@ -345,11 +408,11 @@ Select supports both string and numeric option values. When using numeric values
|
|
|
345
408
|
|
|
346
409
|
```tsx
|
|
347
410
|
<Stack spacing={4}>
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
</Stack>
|
|
411
|
+
<Select defaultValue={1} options={numericOptions} />
|
|
412
|
+
<Select defaultValue={1} variant="plain" options={numericOptions} />
|
|
413
|
+
<Select defaultValue={1} variant="soft" options={numericOptions} />
|
|
414
|
+
<Select defaultValue={1} variant="solid" options={numericOptions} />
|
|
415
|
+
</Stack>
|
|
353
416
|
```
|
|
354
417
|
|
|
355
418
|
```tsx
|
|
@@ -359,7 +422,7 @@ const numericOptions = [
|
|
|
359
422
|
{ value: 3, label: 'Option 3' },
|
|
360
423
|
];
|
|
361
424
|
|
|
362
|
-
<Select options={numericOptions} defaultValue={1}
|
|
425
|
+
<Select options={numericOptions} defaultValue={1} />;
|
|
363
426
|
```
|
|
364
427
|
|
|
365
428
|
## Form with Validation
|
|
@@ -546,25 +609,27 @@ function LocationSelect() {
|
|
|
546
609
|
|
|
547
610
|
### Key Props
|
|
548
611
|
|
|
549
|
-
| Prop | Type
|
|
550
|
-
| ---------------- |
|
|
551
|
-
| `options` | `OptionType[]`
|
|
552
|
-
| `value` | `InferOptionValue<OptionType> \| InferOptionValue<OptionType>[]`
|
|
553
|
-
| `defaultValue` | `InferOptionValue<OptionType> \| InferOptionValue<OptionType>[]`
|
|
554
|
-
| `onChange` | `(event: { target: { name?, value } }, newValue) => void`
|
|
555
|
-
| `multiple` | `boolean`
|
|
556
|
-
| `label` | `string`
|
|
557
|
-
| `helperText` | `string`
|
|
558
|
-
| `error` | `boolean`
|
|
559
|
-
| `required` | `boolean`
|
|
560
|
-
| `disabled` | `boolean`
|
|
561
|
-
| `placeholder` | `string`
|
|
562
|
-
| `size` | `'sm' \| 'md' \| 'lg'`
|
|
563
|
-
| `variant` | `'outlined' \| 'plain' \| 'solid' \| 'soft'`
|
|
564
|
-
| `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'`
|
|
565
|
-
| `startDecorator` | `ReactNode`
|
|
566
|
-
| `endDecorator` | `ReactNode`
|
|
567
|
-
| `
|
|
612
|
+
| Prop | Type | Default | Description |
|
|
613
|
+
| ---------------- | ----------------------------------------------------------------------- | ----------------- | -------------------------------------------------------------- |
|
|
614
|
+
| `options` | `OptionType[]` | `[]` | Array of options (objects or primitives) |
|
|
615
|
+
| `value` | `InferOptionValue<OptionType> \| InferOptionValue<OptionType>[]` | - | Selected value(s) for controlled mode |
|
|
616
|
+
| `defaultValue` | `InferOptionValue<OptionType> \| InferOptionValue<OptionType>[]` | - | Initial value for uncontrolled mode |
|
|
617
|
+
| `onChange` | `(event: { target: { name?, value } }, newValue) => void` | - | Callback when selection changes |
|
|
618
|
+
| `multiple` | `boolean` | `false` | Allow multiple selections (value becomes an array) |
|
|
619
|
+
| `label` | `string` | - | Form label displayed above the select |
|
|
620
|
+
| `helperText` | `string` | - | Helper text displayed below the select |
|
|
621
|
+
| `error` | `boolean` | `false` | Applies danger color to indicate validation error |
|
|
622
|
+
| `required` | `boolean` | `false` | Marks the field as required (adds asterisk to label) |
|
|
623
|
+
| `disabled` | `boolean` | `false` | Disables the select |
|
|
624
|
+
| `placeholder` | `string` | `'Choose one...'` | Placeholder text when no value is selected |
|
|
625
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Select size |
|
|
626
|
+
| `variant` | `'outlined' \| 'plain' \| 'solid' \| 'soft'` | `'outlined'` | Visual style variant |
|
|
627
|
+
| `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | `'neutral'` | Color scheme |
|
|
628
|
+
| `startDecorator` | `ReactNode` | - | Content rendered before the select trigger text |
|
|
629
|
+
| `endDecorator` | `ReactNode` | - | Content rendered after the select trigger text |
|
|
630
|
+
| `id` | `string` | - | Seeds deterministic ids: button `id`, label `${id}-label` |
|
|
631
|
+
| `slotProps` | `{ formControl?, formLabel?, formHelperText?, button?, listbox?, ... }` | - | Props forwarded to composed wrapper slots and Joy Select slots |
|
|
632
|
+
| `sx` | `SxProps` | - | Custom styles using the MUI system |
|
|
568
633
|
|
|
569
634
|
### Option Type
|
|
570
635
|
|
|
@@ -588,19 +653,20 @@ const options = [
|
|
|
588
653
|
{ value: 2, label: 'Option 2' },
|
|
589
654
|
] as const;
|
|
590
655
|
|
|
591
|
-
<Select<typeof options[number], false>
|
|
656
|
+
<Select<(typeof options)[number], false>
|
|
592
657
|
options={options}
|
|
593
658
|
onChange={(e, val) => {
|
|
594
659
|
// val is typed as number
|
|
595
660
|
}}
|
|
596
|
-
|
|
661
|
+
/>;
|
|
597
662
|
```
|
|
598
663
|
|
|
599
664
|
> **Note**: Select also accepts all Joy UI Select props.
|
|
600
665
|
|
|
601
666
|
## Accessibility
|
|
602
667
|
|
|
603
|
-
- **Label association**: When you use the `label` prop, the component automatically connects the label to the select element via `aria-labelledby
|
|
668
|
+
- **Label association**: When you use the `label` prop, the component automatically connects the label to the select element via `aria-labelledby` (the internal `FormControl` propagates a `labelId` to both the label and the button slot). You do not need to wire `useId` or a custom `FormLabel` externally. Always provide a label for screen reader users.
|
|
669
|
+
- **Deterministic ids for tests**: Pass `id` (or `slotProps.formControl.id`) to fix the generated ids, so `byLabelText` / `byRole('combobox', { name })` resolve to a stable accessible name.
|
|
604
670
|
- **Keyboard navigation**: The select can be opened with Enter or Space, navigated with Arrow Up/Down and Home/End, confirmed with Enter, and dismissed with Escape.
|
|
605
671
|
- **Error announcement**: When `error` is set, `aria-invalid` is applied. Pair it with a descriptive `helperText` so assistive technology can announce the error reason.
|
|
606
672
|
- **Required state**: The `required` prop adds `aria-required` and a visible asterisk to the label, communicating the requirement both visually and programmatically.
|