@ceed/ads 1.20.0 → 1.20.1-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.
- package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
- package/dist/components/data-display/Markdown.md +832 -0
- package/dist/components/feedback/Dialog.md +605 -3
- package/dist/components/feedback/Modal.md +656 -24
- package/dist/components/feedback/llms.txt +1 -1
- package/dist/components/inputs/Autocomplete.md +734 -2
- package/dist/components/inputs/Calendar.md +655 -1
- package/dist/components/inputs/DatePicker.md +699 -3
- package/dist/components/inputs/DateRangePicker.md +815 -1
- package/dist/components/inputs/MonthPicker.md +626 -4
- package/dist/components/inputs/MonthRangePicker.md +682 -4
- package/dist/components/inputs/Select.md +600 -0
- package/dist/components/layout/Container.md +507 -0
- package/dist/components/navigation/Breadcrumbs.md +582 -0
- package/dist/components/navigation/IconMenuButton.md +693 -0
- package/dist/components/navigation/InsetDrawer.md +1150 -3
- package/dist/components/navigation/Link.md +526 -0
- package/dist/components/navigation/MenuButton.md +632 -0
- package/dist/components/navigation/NavigationGroup.md +401 -1
- package/dist/components/navigation/NavigationItem.md +311 -0
- package/dist/components/navigation/Navigator.md +373 -0
- package/dist/components/navigation/Pagination.md +521 -0
- package/dist/components/navigation/ProfileMenu.md +605 -0
- package/dist/components/navigation/Tabs.md +609 -7
- package/dist/components/surfaces/Accordions.md +947 -3
- package/dist/index.cjs +3 -1
- package/dist/index.js +3 -1
- package/dist/llms.txt +1 -1
- package/framer/index.js +1 -1
- package/package.json +3 -2
|
@@ -2,6 +2,60 @@
|
|
|
2
2
|
|
|
3
3
|
## Introduction
|
|
4
4
|
|
|
5
|
+
The Tabs component provides a way to organize content into separate views where only one view is visible at a time. Built on Joy UI's Tabs, TabList, Tab, and TabPanel components, it enables users to switch between different sections of related content without leaving the current page. Tabs are ideal for organizing related information that doesn't need to be viewed simultaneously.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
<Tabs {...args} defaultValue={0}>
|
|
9
|
+
<TabList>
|
|
10
|
+
<Tab color={color} variant={variant}>
|
|
11
|
+
First Tab
|
|
12
|
+
</Tab>
|
|
13
|
+
<Tab color={color} variant={variant}>
|
|
14
|
+
Second Tab
|
|
15
|
+
</Tab>
|
|
16
|
+
<Tab color={color} variant={variant}>
|
|
17
|
+
Third Tab
|
|
18
|
+
</Tab>
|
|
19
|
+
</TabList>
|
|
20
|
+
<TabPanel value={0}>Content for the first tab panel.</TabPanel>
|
|
21
|
+
<TabPanel value={1}>Content for the second tab panel.</TabPanel>
|
|
22
|
+
<TabPanel value={2}>Content for the third tab panel.</TabPanel>
|
|
23
|
+
</Tabs>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| Field | Description | Default |
|
|
27
|
+
| ------- | ----------- | --------- |
|
|
28
|
+
| color | — | "primary" |
|
|
29
|
+
| size | — | "md" |
|
|
30
|
+
| variant | — | "plain" |
|
|
31
|
+
|
|
32
|
+
## Usage
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { Tabs, TabList, Tab, TabPanel } from '@ceed/ads';
|
|
36
|
+
|
|
37
|
+
function MyComponent() {
|
|
38
|
+
return (
|
|
39
|
+
<Tabs defaultValue={0}>
|
|
40
|
+
<TabList>
|
|
41
|
+
<Tab>First Tab</Tab>
|
|
42
|
+
<Tab>Second Tab</Tab>
|
|
43
|
+
<Tab>Third Tab</Tab>
|
|
44
|
+
</TabList>
|
|
45
|
+
<TabPanel value={0}>Content for the first tab</TabPanel>
|
|
46
|
+
<TabPanel value={1}>Content for the second tab</TabPanel>
|
|
47
|
+
<TabPanel value={2}>Content for the third tab</TabPanel>
|
|
48
|
+
</Tabs>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Examples
|
|
54
|
+
|
|
55
|
+
### Basic Tabs
|
|
56
|
+
|
|
57
|
+
Default tab navigation with horizontal layout.
|
|
58
|
+
|
|
5
59
|
```tsx
|
|
6
60
|
<Tabs {...args}>
|
|
7
61
|
<TabList>
|
|
@@ -21,14 +75,562 @@
|
|
|
21
75
|
</Tabs>
|
|
22
76
|
```
|
|
23
77
|
|
|
24
|
-
|
|
25
|
-
| ------- | ----------- | --------- |
|
|
26
|
-
| color | — | "primary" |
|
|
27
|
-
| size | — | "md" |
|
|
28
|
-
| variant | — | "plain" |
|
|
78
|
+
### Variants
|
|
29
79
|
|
|
30
|
-
|
|
80
|
+
Tabs support different visual styles through variants.
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
<div style={{
|
|
84
|
+
display: 'flex',
|
|
85
|
+
flexDirection: 'column',
|
|
86
|
+
gap: 24
|
|
87
|
+
}}>
|
|
88
|
+
<Tabs defaultValue={0}>
|
|
89
|
+
<TabList variant="plain">
|
|
90
|
+
<Tab variant="plain">Plain</Tab>
|
|
91
|
+
<Tab variant="plain">Tabs</Tab>
|
|
92
|
+
<Tab variant="plain">Example</Tab>
|
|
93
|
+
</TabList>
|
|
94
|
+
</Tabs>
|
|
95
|
+
<Tabs defaultValue={0}>
|
|
96
|
+
<TabList variant="outlined">
|
|
97
|
+
<Tab variant="outlined">Outlined</Tab>
|
|
98
|
+
<Tab variant="outlined">Tabs</Tab>
|
|
99
|
+
<Tab variant="outlined">Example</Tab>
|
|
100
|
+
</TabList>
|
|
101
|
+
</Tabs>
|
|
102
|
+
<Tabs defaultValue={0}>
|
|
103
|
+
<TabList variant="soft">
|
|
104
|
+
<Tab variant="soft">Soft</Tab>
|
|
105
|
+
<Tab variant="soft">Tabs</Tab>
|
|
106
|
+
<Tab variant="soft">Example</Tab>
|
|
107
|
+
</TabList>
|
|
108
|
+
</Tabs>
|
|
109
|
+
<Tabs defaultValue={0}>
|
|
110
|
+
<TabList variant="solid">
|
|
111
|
+
<Tab variant="solid">Solid</Tab>
|
|
112
|
+
<Tab variant="solid">Tabs</Tab>
|
|
113
|
+
<Tab variant="solid">Example</Tab>
|
|
114
|
+
</TabList>
|
|
115
|
+
</Tabs>
|
|
116
|
+
</div>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Sizes
|
|
120
|
+
|
|
121
|
+
Tabs come in different sizes to fit various use cases.
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
<div style={{
|
|
125
|
+
display: 'flex',
|
|
126
|
+
flexDirection: 'column',
|
|
127
|
+
gap: 24
|
|
128
|
+
}}>
|
|
129
|
+
<Tabs defaultValue={0} size="sm">
|
|
130
|
+
<TabList>
|
|
131
|
+
<Tab>Small</Tab>
|
|
132
|
+
<Tab>Size</Tab>
|
|
133
|
+
<Tab>Tabs</Tab>
|
|
134
|
+
</TabList>
|
|
135
|
+
</Tabs>
|
|
136
|
+
<Tabs defaultValue={0} size="md">
|
|
137
|
+
<TabList>
|
|
138
|
+
<Tab>Medium</Tab>
|
|
139
|
+
<Tab>Size</Tab>
|
|
140
|
+
<Tab>Tabs</Tab>
|
|
141
|
+
</TabList>
|
|
142
|
+
</Tabs>
|
|
143
|
+
<Tabs defaultValue={0} size="lg">
|
|
144
|
+
<TabList>
|
|
145
|
+
<Tab>Large</Tab>
|
|
146
|
+
<Tab>Size</Tab>
|
|
147
|
+
<Tab>Tabs</Tab>
|
|
148
|
+
</TabList>
|
|
149
|
+
</Tabs>
|
|
150
|
+
</div>
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Colors
|
|
154
|
+
|
|
155
|
+
Apply semantic colors to tabs.
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
<div style={{
|
|
159
|
+
display: 'flex',
|
|
160
|
+
flexDirection: 'column',
|
|
161
|
+
gap: 24
|
|
162
|
+
}}>
|
|
163
|
+
<Tabs defaultValue={0}>
|
|
164
|
+
<TabList>
|
|
165
|
+
<Tab color="primary">Primary</Tab>
|
|
166
|
+
<Tab color="primary">Tabs</Tab>
|
|
167
|
+
</TabList>
|
|
168
|
+
</Tabs>
|
|
169
|
+
<Tabs defaultValue={0}>
|
|
170
|
+
<TabList>
|
|
171
|
+
<Tab color="neutral">Neutral</Tab>
|
|
172
|
+
<Tab color="neutral">Tabs</Tab>
|
|
173
|
+
</TabList>
|
|
174
|
+
</Tabs>
|
|
175
|
+
<Tabs defaultValue={0}>
|
|
176
|
+
<TabList>
|
|
177
|
+
<Tab color="success">Success</Tab>
|
|
178
|
+
<Tab color="success">Tabs</Tab>
|
|
179
|
+
</TabList>
|
|
180
|
+
</Tabs>
|
|
181
|
+
<Tabs defaultValue={0}>
|
|
182
|
+
<TabList>
|
|
183
|
+
<Tab color="warning">Warning</Tab>
|
|
184
|
+
<Tab color="warning">Tabs</Tab>
|
|
185
|
+
</TabList>
|
|
186
|
+
</Tabs>
|
|
187
|
+
<Tabs defaultValue={0}>
|
|
188
|
+
<TabList>
|
|
189
|
+
<Tab color="danger">Danger</Tab>
|
|
190
|
+
<Tab color="danger">Tabs</Tab>
|
|
191
|
+
</TabList>
|
|
192
|
+
</Tabs>
|
|
193
|
+
</div>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### With Decorators
|
|
197
|
+
|
|
198
|
+
Add icons or other elements to tab labels.
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
<Tabs {...args}>
|
|
202
|
+
<TabList>
|
|
203
|
+
<Tab startDecorator={<Call />} color={color} variant={variant}>
|
|
204
|
+
Tab1
|
|
205
|
+
</Tab>
|
|
206
|
+
<Tab endDecorator={<Sms />} color={color} variant={variant}>
|
|
207
|
+
Tab2
|
|
208
|
+
</Tab>
|
|
209
|
+
<Tab startDecorator={<Email />} endDecorator={<MoreVert />} color={color} variant={variant}>
|
|
210
|
+
Tab3
|
|
211
|
+
</Tab>
|
|
212
|
+
</TabList>
|
|
213
|
+
<TabPanel value={0}>Tab list1</TabPanel>
|
|
214
|
+
<TabPanel value={1}>Tab list2</TabPanel>
|
|
215
|
+
<TabPanel value={2}>Tab list3</TabPanel>
|
|
216
|
+
</Tabs>
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Vertical Orientation
|
|
220
|
+
|
|
221
|
+
Tabs can be arranged vertically for sidebar-style navigation.
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
<Tabs defaultValue={0} orientation="vertical" sx={{
|
|
225
|
+
minWidth: 300
|
|
226
|
+
}}>
|
|
227
|
+
<TabList>
|
|
228
|
+
<Tab>Profile</Tab>
|
|
229
|
+
<Tab>Settings</Tab>
|
|
230
|
+
<Tab>Notifications</Tab>
|
|
231
|
+
</TabList>
|
|
232
|
+
<TabPanel value={0}>Profile content</TabPanel>
|
|
233
|
+
<TabPanel value={1}>Settings content</TabPanel>
|
|
234
|
+
<TabPanel value={2}>Notifications content</TabPanel>
|
|
235
|
+
</Tabs>
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Disabled Tabs
|
|
239
|
+
|
|
240
|
+
Individual tabs can be disabled while keeping others active.
|
|
241
|
+
|
|
242
|
+
```tsx
|
|
243
|
+
<Tabs defaultValue={0}>
|
|
244
|
+
<TabList>
|
|
245
|
+
<Tab>Active Tab</Tab>
|
|
246
|
+
<Tab disabled>Disabled Tab</Tab>
|
|
247
|
+
<Tab>Another Tab</Tab>
|
|
248
|
+
</TabList>
|
|
249
|
+
<TabPanel value={0}>First panel content</TabPanel>
|
|
250
|
+
<TabPanel value={1}>Second panel content (disabled)</TabPanel>
|
|
251
|
+
<TabPanel value={2}>Third panel content</TabPanel>
|
|
252
|
+
</Tabs>
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Controlled Tabs
|
|
256
|
+
|
|
257
|
+
Programmatically control the active tab.
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
<div>
|
|
261
|
+
<Tabs value={value} onChange={(event, newValue) => setValue(newValue as number)}>
|
|
262
|
+
<TabList>
|
|
263
|
+
<Tab>First</Tab>
|
|
264
|
+
<Tab>Second</Tab>
|
|
265
|
+
<Tab>Third</Tab>
|
|
266
|
+
</TabList>
|
|
267
|
+
<TabPanel value={0}>First panel</TabPanel>
|
|
268
|
+
<TabPanel value={1}>Second panel</TabPanel>
|
|
269
|
+
<TabPanel value={2}>Third panel</TabPanel>
|
|
270
|
+
</Tabs>
|
|
271
|
+
<div style={{
|
|
272
|
+
marginTop: 16
|
|
273
|
+
}}>Current tab index: {value}</div>
|
|
274
|
+
</div>
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
## When to Use
|
|
278
|
+
|
|
279
|
+
### ✅ Good Use Cases
|
|
280
|
+
|
|
281
|
+
- **Related content sections**: When content can be logically grouped and users don't need to see all sections at once
|
|
282
|
+
- **Settings pages**: Organizing different categories of settings (Profile, Security, Notifications)
|
|
283
|
+
- **Dashboard views**: Switching between different data views or time periods
|
|
284
|
+
- **Product details**: Showing Description, Specifications, Reviews as separate tabs
|
|
285
|
+
- **Form sections**: Breaking long forms into logical steps (not for strict wizard flows)
|
|
286
|
+
- **Code examples**: Showing code in different languages or frameworks
|
|
287
|
+
|
|
288
|
+
### ❌ When Not to Use
|
|
289
|
+
|
|
290
|
+
- **Primary navigation**: Use a navigation menu or sidebar for main app navigation
|
|
291
|
+
- **Sequential workflows**: Use Stepper for multi-step processes that must be completed in order
|
|
292
|
+
- **Comparing content**: If users need to see multiple sections simultaneously, use accordions or show all content
|
|
293
|
+
- **Very few items**: If there are only 2 options, consider using a toggle or radio buttons
|
|
294
|
+
- **Many items**: More than 5-6 tabs become hard to navigate; consider a dropdown or nested navigation
|
|
295
|
+
- **Mobile layouts**: Consider alternative patterns like accordions or stacked sections on small screens
|
|
296
|
+
|
|
297
|
+
## Common Use Cases
|
|
298
|
+
|
|
299
|
+
### Settings Page
|
|
300
|
+
|
|
301
|
+
```tsx
|
|
302
|
+
function SettingsPage() {
|
|
303
|
+
return (
|
|
304
|
+
<Tabs defaultValue={0}>
|
|
305
|
+
<TabList>
|
|
306
|
+
<Tab startDecorator={<PersonIcon />}>Profile</Tab>
|
|
307
|
+
<Tab startDecorator={<SecurityIcon />}>Security</Tab>
|
|
308
|
+
<Tab startDecorator={<NotificationsIcon />}>Notifications</Tab>
|
|
309
|
+
<Tab startDecorator={<PaletteIcon />}>Appearance</Tab>
|
|
310
|
+
</TabList>
|
|
311
|
+
<TabPanel value={0}>
|
|
312
|
+
<ProfileSettings />
|
|
313
|
+
</TabPanel>
|
|
314
|
+
<TabPanel value={1}>
|
|
315
|
+
<SecuritySettings />
|
|
316
|
+
</TabPanel>
|
|
317
|
+
<TabPanel value={2}>
|
|
318
|
+
<NotificationSettings />
|
|
319
|
+
</TabPanel>
|
|
320
|
+
<TabPanel value={3}>
|
|
321
|
+
<AppearanceSettings />
|
|
322
|
+
</TabPanel>
|
|
323
|
+
</Tabs>
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Product Detail Page
|
|
329
|
+
|
|
330
|
+
```tsx
|
|
331
|
+
function ProductDetails({ product }) {
|
|
332
|
+
return (
|
|
333
|
+
<Tabs defaultValue={0}>
|
|
334
|
+
<TabList>
|
|
335
|
+
<Tab>Description</Tab>
|
|
336
|
+
<Tab>Specifications</Tab>
|
|
337
|
+
<Tab>Reviews ({product.reviewCount})</Tab>
|
|
338
|
+
<Tab>Q&A</Tab>
|
|
339
|
+
</TabList>
|
|
340
|
+
<TabPanel value={0}>
|
|
341
|
+
<Typography>{product.description}</Typography>
|
|
342
|
+
</TabPanel>
|
|
343
|
+
<TabPanel value={1}>
|
|
344
|
+
<SpecificationTable specs={product.specifications} />
|
|
345
|
+
</TabPanel>
|
|
346
|
+
<TabPanel value={2}>
|
|
347
|
+
<ReviewList reviews={product.reviews} />
|
|
348
|
+
</TabPanel>
|
|
349
|
+
<TabPanel value={3}>
|
|
350
|
+
<QASection productId={product.id} />
|
|
351
|
+
</TabPanel>
|
|
352
|
+
</Tabs>
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Dashboard with Time Filters
|
|
358
|
+
|
|
359
|
+
```tsx
|
|
360
|
+
function DashboardTabs() {
|
|
361
|
+
const [timeRange, setTimeRange] = useState('week');
|
|
362
|
+
|
|
363
|
+
return (
|
|
364
|
+
<Tabs value={timeRange} onChange={(e, val) => setTimeRange(val as string)}>
|
|
365
|
+
<TabList>
|
|
366
|
+
<Tab value="day">Today</Tab>
|
|
367
|
+
<Tab value="week">This Week</Tab>
|
|
368
|
+
<Tab value="month">This Month</Tab>
|
|
369
|
+
<Tab value="year">This Year</Tab>
|
|
370
|
+
</TabList>
|
|
371
|
+
<TabPanel value="day">
|
|
372
|
+
<DailyStats />
|
|
373
|
+
</TabPanel>
|
|
374
|
+
<TabPanel value="week">
|
|
375
|
+
<WeeklyStats />
|
|
376
|
+
</TabPanel>
|
|
377
|
+
<TabPanel value="month">
|
|
378
|
+
<MonthlyStats />
|
|
379
|
+
</TabPanel>
|
|
380
|
+
<TabPanel value="year">
|
|
381
|
+
<YearlyStats />
|
|
382
|
+
</TabPanel>
|
|
383
|
+
</Tabs>
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Code Examples
|
|
389
|
+
|
|
390
|
+
```tsx
|
|
391
|
+
function CodeExamples() {
|
|
392
|
+
return (
|
|
393
|
+
<Tabs defaultValue="react">
|
|
394
|
+
<TabList>
|
|
395
|
+
<Tab value="react">React</Tab>
|
|
396
|
+
<Tab value="vue">Vue</Tab>
|
|
397
|
+
<Tab value="angular">Angular</Tab>
|
|
398
|
+
</TabList>
|
|
399
|
+
<TabPanel value="react">
|
|
400
|
+
<CodeBlock language="jsx">{reactCode}</CodeBlock>
|
|
401
|
+
</TabPanel>
|
|
402
|
+
<TabPanel value="vue">
|
|
403
|
+
<CodeBlock language="vue">{vueCode}</CodeBlock>
|
|
404
|
+
</TabPanel>
|
|
405
|
+
<TabPanel value="angular">
|
|
406
|
+
<CodeBlock language="typescript">{angularCode}</CodeBlock>
|
|
407
|
+
</TabPanel>
|
|
408
|
+
</Tabs>
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Vertical Sidebar Navigation
|
|
414
|
+
|
|
415
|
+
```tsx
|
|
416
|
+
function SidebarTabs() {
|
|
417
|
+
return (
|
|
418
|
+
<Box sx={{ display: 'flex' }}>
|
|
419
|
+
<Tabs orientation="vertical" defaultValue={0} sx={{ minWidth: 200 }}>
|
|
420
|
+
<TabList>
|
|
421
|
+
<Tab startDecorator={<DashboardIcon />}>Dashboard</Tab>
|
|
422
|
+
<Tab startDecorator={<AnalyticsIcon />}>Analytics</Tab>
|
|
423
|
+
<Tab startDecorator={<ReportsIcon />}>Reports</Tab>
|
|
424
|
+
<Tab startDecorator={<SettingsIcon />}>Settings</Tab>
|
|
425
|
+
</TabList>
|
|
426
|
+
</Tabs>
|
|
427
|
+
<Box sx={{ flex: 1, p: 2 }}>
|
|
428
|
+
<TabPanel value={0}>Dashboard content</TabPanel>
|
|
429
|
+
<TabPanel value={1}>Analytics content</TabPanel>
|
|
430
|
+
<TabPanel value={2}>Reports content</TabPanel>
|
|
431
|
+
<TabPanel value={3}>Settings content</TabPanel>
|
|
432
|
+
</Box>
|
|
433
|
+
</Box>
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
## Component Structure
|
|
439
|
+
|
|
440
|
+
Tabs uses a composition pattern with multiple sub-components:
|
|
441
|
+
|
|
442
|
+
```tsx
|
|
443
|
+
<Tabs> {/* Container - manages state */}
|
|
444
|
+
<TabList> {/* Tab button container */}
|
|
445
|
+
<Tab>Tab 1</Tab> {/* Individual tab buttons */}
|
|
446
|
+
<Tab>Tab 2</Tab>
|
|
447
|
+
</TabList>
|
|
448
|
+
<TabPanel value={0}> {/* Content panels */}
|
|
449
|
+
Content 1
|
|
450
|
+
</TabPanel>
|
|
451
|
+
<TabPanel value={1}>
|
|
452
|
+
Content 2
|
|
453
|
+
</TabPanel>
|
|
454
|
+
</Tabs>
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
## Props and Customization
|
|
458
|
+
|
|
459
|
+
### Tabs Props
|
|
460
|
+
|
|
461
|
+
| Prop | Type | Default | Description |
|
|
462
|
+
| -------------- | ---------------------------- | -------------- | ----------------------------------- |
|
|
463
|
+
| `defaultValue` | `string \| number` | - | Default selected tab (uncontrolled) |
|
|
464
|
+
| `value` | `string \| number` | - | Selected tab (controlled) |
|
|
465
|
+
| `onChange` | `function` | - | Callback when tab changes |
|
|
466
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Tab layout direction |
|
|
467
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of all child components |
|
|
468
|
+
|
|
469
|
+
### Tab Props
|
|
470
|
+
|
|
471
|
+
| Prop | Type | Default | Description |
|
|
472
|
+
| ---------------- | -------------------------------------------------------------- | --------- | ---------------------------------- |
|
|
473
|
+
| `value` | `string \| number` | - | Tab identifier (defaults to index) |
|
|
474
|
+
| `variant` | `'plain' \| 'outlined' \| 'soft' \| 'solid'` | `'plain'` | Visual style |
|
|
475
|
+
| `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | - | Color scheme |
|
|
476
|
+
| `disabled` | `boolean` | `false` | Disable the tab |
|
|
477
|
+
| `startDecorator` | `ReactNode` | - | Element before tab label |
|
|
478
|
+
| `endDecorator` | `ReactNode` | - | Element after tab label |
|
|
479
|
+
|
|
480
|
+
### TabPanel Props
|
|
481
|
+
|
|
482
|
+
| Prop | Type | Default | Description |
|
|
483
|
+
| ------------- | ------------------ | ------- | ----------------------------- |
|
|
484
|
+
| `value` | `string \| number` | - | Matching tab value |
|
|
485
|
+
| `keepMounted` | `boolean` | `false` | Keep panel in DOM when hidden |
|
|
486
|
+
|
|
487
|
+
### Custom Styling
|
|
488
|
+
|
|
489
|
+
```tsx
|
|
490
|
+
<Tabs
|
|
491
|
+
sx={{
|
|
492
|
+
'--Tabs-gap': '8px',
|
|
493
|
+
}}
|
|
494
|
+
>
|
|
495
|
+
<TabList
|
|
496
|
+
sx={{
|
|
497
|
+
borderBottom: '1px solid',
|
|
498
|
+
borderColor: 'divider',
|
|
499
|
+
}}
|
|
500
|
+
>
|
|
501
|
+
<Tab
|
|
502
|
+
sx={{
|
|
503
|
+
'&.Mui-selected': {
|
|
504
|
+
borderBottom: '2px solid',
|
|
505
|
+
borderColor: 'primary.500',
|
|
506
|
+
},
|
|
507
|
+
}}
|
|
508
|
+
>
|
|
509
|
+
Custom Tab
|
|
510
|
+
</Tab>
|
|
511
|
+
</TabList>
|
|
512
|
+
</Tabs>
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
## Accessibility
|
|
516
|
+
|
|
517
|
+
Tabs components follow WAI-ARIA Tabs pattern for comprehensive accessibility:
|
|
518
|
+
|
|
519
|
+
### ARIA Attributes
|
|
520
|
+
|
|
521
|
+
- `role="tablist"` on TabList
|
|
522
|
+
- `role="tab"` on each Tab
|
|
523
|
+
- `role="tabpanel"` on each TabPanel
|
|
524
|
+
- `aria-selected` indicates the active tab
|
|
525
|
+
- `aria-controls` links tabs to their panels
|
|
526
|
+
- `aria-labelledby` links panels to their tabs
|
|
527
|
+
|
|
528
|
+
### Keyboard Navigation
|
|
529
|
+
|
|
530
|
+
- **Tab**: Move focus to the tab list, then to the active panel
|
|
531
|
+
- **Arrow Left/Right**: Move between tabs (horizontal orientation)
|
|
532
|
+
- **Arrow Up/Down**: Move between tabs (vertical orientation)
|
|
533
|
+
- **Home**: Move to first tab
|
|
534
|
+
- **End**: Move to last tab
|
|
535
|
+
- **Enter/Space**: Activate the focused tab
|
|
536
|
+
|
|
537
|
+
### Screen Reader Support
|
|
31
538
|
|
|
32
539
|
```tsx
|
|
33
|
-
|
|
540
|
+
<Tabs aria-label="Account settings tabs">
|
|
541
|
+
<TabList>
|
|
542
|
+
<Tab>Profile</Tab>
|
|
543
|
+
<Tab>Security</Tab>
|
|
544
|
+
</TabList>
|
|
545
|
+
<TabPanel value={0}>
|
|
546
|
+
<h2 id="profile-heading">Profile Settings</h2>
|
|
547
|
+
{/* Content */}
|
|
548
|
+
</TabPanel>
|
|
549
|
+
</Tabs>
|
|
34
550
|
```
|
|
551
|
+
|
|
552
|
+
## Best Practices
|
|
553
|
+
|
|
554
|
+
### ✅ Do
|
|
555
|
+
|
|
556
|
+
1. **Use clear, concise labels**: Tab labels should clearly describe the content
|
|
557
|
+
|
|
558
|
+
```tsx
|
|
559
|
+
// ✅ Good: Clear labels
|
|
560
|
+
<Tab>Account Settings</Tab>
|
|
561
|
+
<Tab>Notifications</Tab>
|
|
562
|
+
|
|
563
|
+
// ❌ Bad: Vague labels
|
|
564
|
+
<Tab>Tab 1</Tab>
|
|
565
|
+
<Tab>Other</Tab>
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
2. **Keep tab count manageable**: Limit to 5-6 tabs maximum
|
|
569
|
+
|
|
570
|
+
3. **Order tabs logically**: Place most important or frequently used tabs first
|
|
571
|
+
|
|
572
|
+
4. **Use consistent styling**: All tabs should have the same visual weight
|
|
573
|
+
|
|
574
|
+
5. **Show active state clearly**: Users should always know which tab is selected
|
|
575
|
+
|
|
576
|
+
### ❌ Don't
|
|
577
|
+
|
|
578
|
+
1. **Don't hide critical information**: Important content shouldn't be buried in secondary tabs
|
|
579
|
+
|
|
580
|
+
2. **Don't use for sequential processes**: Use Stepper for ordered workflows
|
|
581
|
+
|
|
582
|
+
```tsx
|
|
583
|
+
// ❌ Bad: Sequential steps as tabs
|
|
584
|
+
<Tab>Step 1: Personal Info</Tab>
|
|
585
|
+
<Tab>Step 2: Payment</Tab>
|
|
586
|
+
<Tab>Step 3: Confirm</Tab>
|
|
587
|
+
|
|
588
|
+
// ✅ Good: Use Stepper instead
|
|
589
|
+
<Stepper activeStep={activeStep}>
|
|
590
|
+
<Step>Personal Info</Step>
|
|
591
|
+
<Step>Payment</Step>
|
|
592
|
+
<Step>Confirm</Step>
|
|
593
|
+
</Stepper>
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
3. **Don't nest tabs within tabs**: Creates confusing navigation
|
|
597
|
+
|
|
598
|
+
4. **Don't use inconsistent tab counts**: If tabs are dynamic, consider alternative UI patterns
|
|
599
|
+
|
|
600
|
+
## Performance Considerations
|
|
601
|
+
|
|
602
|
+
### Lazy Loading Tab Content
|
|
603
|
+
|
|
604
|
+
By default, inactive tab panels are not rendered. For complex content, this provides automatic lazy loading:
|
|
605
|
+
|
|
606
|
+
```tsx
|
|
607
|
+
<TabPanel value={0}>
|
|
608
|
+
{/* Only rendered when this tab is active */}
|
|
609
|
+
<HeavyComponent />
|
|
610
|
+
</TabPanel>
|
|
611
|
+
```
|
|
612
|
+
|
|
613
|
+
### Keep Mounted
|
|
614
|
+
|
|
615
|
+
Use `keepMounted` when tab content needs to maintain state:
|
|
616
|
+
|
|
617
|
+
```tsx
|
|
618
|
+
<TabPanel value={0} keepMounted>
|
|
619
|
+
{/* Stays in DOM, maintains form state */}
|
|
620
|
+
<FormWithState />
|
|
621
|
+
</TabPanel>
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Avoid Heavy Re-renders
|
|
625
|
+
|
|
626
|
+
Memoize tab content when it depends on complex calculations:
|
|
627
|
+
|
|
628
|
+
```tsx
|
|
629
|
+
const tabContent = useMemo(() => (
|
|
630
|
+
<ExpensiveComponent data={data} />
|
|
631
|
+
), [data]);
|
|
632
|
+
|
|
633
|
+
<TabPanel value={0}>{tabContent}</TabPanel>
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
Tabs provide an intuitive way to organize related content while keeping the interface clean and navigable. Use them thoughtfully to enhance content discoverability without overwhelming users.
|