@ceed/ads 1.29.1 → 1.30.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
- package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
- package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
- package/dist/components/SearchBar/SearchBar.d.ts +21 -0
- package/dist/components/SearchBar/index.d.ts +3 -0
- package/dist/components/data-display/Badge.md +39 -71
- package/dist/components/data-display/DataTable.md +1 -1
- package/dist/components/data-display/InfoSign.md +98 -74
- package/dist/components/data-display/Typography.md +97 -363
- package/dist/components/feedback/Dialog.md +62 -76
- package/dist/components/feedback/Modal.md +44 -259
- package/dist/components/feedback/llms.txt +0 -2
- package/dist/components/index.d.ts +2 -0
- package/dist/components/inputs/Autocomplete.md +107 -356
- package/dist/components/inputs/ButtonGroup.md +106 -115
- package/dist/components/inputs/Calendar.md +459 -98
- package/dist/components/inputs/CurrencyInput.md +5 -183
- package/dist/components/inputs/DatePicker.md +431 -108
- package/dist/components/inputs/DateRangePicker.md +492 -131
- package/dist/components/inputs/FilterMenu.md +19 -169
- package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
- package/dist/components/inputs/IconButton.md +88 -137
- package/dist/components/inputs/Input.md +0 -5
- package/dist/components/inputs/MonthPicker.md +422 -95
- package/dist/components/inputs/MonthRangePicker.md +466 -89
- package/dist/components/inputs/PercentageInput.md +16 -185
- package/dist/components/inputs/RadioButton.md +35 -163
- package/dist/components/inputs/RadioTileGroup.md +61 -150
- package/dist/components/inputs/SearchBar.md +44 -0
- package/dist/components/inputs/Select.md +326 -222
- package/dist/components/inputs/Switch.md +376 -136
- package/dist/components/inputs/Textarea.md +10 -213
- package/dist/components/inputs/Uploader/Uploader.md +66 -145
- package/dist/components/inputs/llms.txt +1 -3
- package/dist/components/navigation/Breadcrumbs.md +322 -80
- package/dist/components/navigation/Dropdown.md +221 -92
- package/dist/components/navigation/IconMenuButton.md +502 -40
- package/dist/components/navigation/InsetDrawer.md +738 -68
- package/dist/components/navigation/Link.md +298 -39
- package/dist/components/navigation/Menu.md +285 -92
- package/dist/components/navigation/MenuButton.md +448 -55
- package/dist/components/navigation/Pagination.md +338 -47
- package/dist/components/navigation/ProfileMenu.md +268 -45
- package/dist/components/navigation/Stepper.md +28 -160
- package/dist/components/navigation/Tabs.md +316 -57
- package/dist/components/surfaces/Sheet.md +334 -151
- package/dist/index.browser.js +15 -13
- package/dist/index.browser.js.map +4 -4
- package/dist/index.cjs +289 -288
- package/dist/index.d.ts +1 -1
- package/dist/index.js +426 -369
- package/dist/llms.txt +1 -8
- package/framer/index.js +1 -1
- package/package.json +16 -15
- package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
- package/dist/components/feedback/CircularProgress.md +0 -257
- package/dist/components/feedback/Skeleton.md +0 -280
- package/dist/components/inputs/FormControl.md +0 -361
- package/dist/components/inputs/RadioList.md +0 -241
- package/dist/components/inputs/Slider.md +0 -334
- package/dist/guides/ThemeProvider.md +0 -116
- package/dist/guides/llms.txt +0 -9
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Tabs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Introduction
|
|
4
4
|
|
|
5
|
-
Tabs
|
|
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
6
|
|
|
7
7
|
```tsx
|
|
8
8
|
<Tabs {...args} defaultValue={0}>
|
|
@@ -50,11 +50,11 @@ function MyComponent() {
|
|
|
50
50
|
}
|
|
51
51
|
```
|
|
52
52
|
|
|
53
|
-
##
|
|
53
|
+
## Examples
|
|
54
54
|
|
|
55
55
|
### Basic Tabs
|
|
56
56
|
|
|
57
|
-
Default
|
|
57
|
+
Default tab navigation with horizontal layout.
|
|
58
58
|
|
|
59
59
|
```tsx
|
|
60
60
|
<Tabs {...args}>
|
|
@@ -77,7 +77,7 @@ Default horizontal tab navigation with tab panels.
|
|
|
77
77
|
|
|
78
78
|
### Variants
|
|
79
79
|
|
|
80
|
-
Tabs support
|
|
80
|
+
Tabs support different visual styles through variants.
|
|
81
81
|
|
|
82
82
|
```tsx
|
|
83
83
|
<div style={{
|
|
@@ -118,7 +118,7 @@ Tabs support `plain`, `outlined`, `soft`, and `solid` visual styles. Apply the v
|
|
|
118
118
|
|
|
119
119
|
### Sizes
|
|
120
120
|
|
|
121
|
-
Tabs come in
|
|
121
|
+
Tabs come in different sizes to fit various use cases.
|
|
122
122
|
|
|
123
123
|
```tsx
|
|
124
124
|
<div style={{
|
|
@@ -152,7 +152,7 @@ Tabs come in `sm`, `md`, and `lg` sizes. Set the `size` prop on the Tabs contain
|
|
|
152
152
|
|
|
153
153
|
### Colors
|
|
154
154
|
|
|
155
|
-
Apply semantic colors
|
|
155
|
+
Apply semantic colors to tabs.
|
|
156
156
|
|
|
157
157
|
```tsx
|
|
158
158
|
<div style={{
|
|
@@ -195,7 +195,7 @@ Apply semantic colors (`primary`, `neutral`, `success`, `warning`, `danger`) to
|
|
|
195
195
|
|
|
196
196
|
### With Decorators
|
|
197
197
|
|
|
198
|
-
Add icons or other elements
|
|
198
|
+
Add icons or other elements to tab labels.
|
|
199
199
|
|
|
200
200
|
```tsx
|
|
201
201
|
<Tabs {...args}>
|
|
@@ -218,7 +218,7 @@ Add icons or other elements before or after the tab label using `startDecorator`
|
|
|
218
218
|
|
|
219
219
|
### Vertical Orientation
|
|
220
220
|
|
|
221
|
-
|
|
221
|
+
Tabs can be arranged vertically for sidebar-style navigation.
|
|
222
222
|
|
|
223
223
|
```tsx
|
|
224
224
|
<Tabs defaultValue={0} orientation="vertical" sx={{
|
|
@@ -237,7 +237,7 @@ Set `orientation="vertical"` on the Tabs container for sidebar-style navigation
|
|
|
237
237
|
|
|
238
238
|
### Disabled Tabs
|
|
239
239
|
|
|
240
|
-
Individual tabs can be disabled
|
|
240
|
+
Individual tabs can be disabled while keeping others active.
|
|
241
241
|
|
|
242
242
|
```tsx
|
|
243
243
|
<Tabs defaultValue={0}>
|
|
@@ -254,7 +254,7 @@ Individual tabs can be disabled with the `disabled` prop while keeping other tab
|
|
|
254
254
|
|
|
255
255
|
### Controlled Tabs
|
|
256
256
|
|
|
257
|
-
|
|
257
|
+
Programmatically control the active tab.
|
|
258
258
|
|
|
259
259
|
```tsx
|
|
260
260
|
<div>
|
|
@@ -274,6 +274,26 @@ Use the `value` and `onChange` props for programmatic control of the active tab.
|
|
|
274
274
|
</div>
|
|
275
275
|
```
|
|
276
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
|
+
|
|
277
297
|
## Common Use Cases
|
|
278
298
|
|
|
279
299
|
### Settings Page
|
|
@@ -286,92 +306,331 @@ function SettingsPage() {
|
|
|
286
306
|
<Tab startDecorator={<PersonIcon />}>Profile</Tab>
|
|
287
307
|
<Tab startDecorator={<SecurityIcon />}>Security</Tab>
|
|
288
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>
|
|
289
339
|
</TabList>
|
|
290
|
-
<TabPanel value={0}
|
|
291
|
-
|
|
292
|
-
|
|
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>
|
|
293
352
|
</Tabs>
|
|
294
353
|
);
|
|
295
354
|
}
|
|
296
355
|
```
|
|
297
356
|
|
|
298
|
-
### Dashboard Time
|
|
357
|
+
### Dashboard with Time Filters
|
|
299
358
|
|
|
300
359
|
```tsx
|
|
301
360
|
function DashboardTabs() {
|
|
302
|
-
const [
|
|
361
|
+
const [timeRange, setTimeRange] = useState('week');
|
|
303
362
|
|
|
304
363
|
return (
|
|
305
|
-
<Tabs value={
|
|
364
|
+
<Tabs value={timeRange} onChange={(e, val) => setTimeRange(val as string)}>
|
|
306
365
|
<TabList>
|
|
307
366
|
<Tab value="day">Today</Tab>
|
|
308
367
|
<Tab value="week">This Week</Tab>
|
|
309
368
|
<Tab value="month">This Month</Tab>
|
|
369
|
+
<Tab value="year">This Year</Tab>
|
|
310
370
|
</TabList>
|
|
311
|
-
<TabPanel value="day"
|
|
312
|
-
|
|
313
|
-
|
|
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>
|
|
314
383
|
</Tabs>
|
|
315
384
|
);
|
|
316
385
|
}
|
|
317
386
|
```
|
|
318
387
|
|
|
319
|
-
###
|
|
388
|
+
### Code Examples
|
|
320
389
|
|
|
321
390
|
```tsx
|
|
322
|
-
function
|
|
391
|
+
function CodeExamples() {
|
|
323
392
|
return (
|
|
324
|
-
<Tabs
|
|
393
|
+
<Tabs defaultValue="react">
|
|
325
394
|
<TabList>
|
|
326
|
-
<Tab
|
|
327
|
-
<Tab
|
|
328
|
-
<Tab
|
|
395
|
+
<Tab value="react">React</Tab>
|
|
396
|
+
<Tab value="vue">Vue</Tab>
|
|
397
|
+
<Tab value="angular">Angular</Tab>
|
|
329
398
|
</TabList>
|
|
330
|
-
<TabPanel value=
|
|
331
|
-
|
|
332
|
-
|
|
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>
|
|
333
408
|
</Tabs>
|
|
334
409
|
);
|
|
335
410
|
}
|
|
336
411
|
```
|
|
337
412
|
|
|
338
|
-
|
|
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
|
+
```
|
|
339
437
|
|
|
340
|
-
|
|
438
|
+
## Component Structure
|
|
341
439
|
|
|
342
|
-
|
|
343
|
-
{/* ✅ Good: Descriptive labels */}
|
|
344
|
-
<Tab>Account Settings</Tab>
|
|
345
|
-
<Tab>Notifications</Tab>
|
|
440
|
+
Tabs uses a composition pattern with multiple sub-components:
|
|
346
441
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
<
|
|
350
|
-
|
|
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
|
+
```
|
|
351
456
|
|
|
352
|
-
|
|
457
|
+
## Props and Customization
|
|
353
458
|
|
|
354
|
-
|
|
459
|
+
### Tabs Props
|
|
355
460
|
|
|
356
|
-
|
|
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 |
|
|
357
468
|
|
|
358
|
-
|
|
359
|
-
{/* ❌ Bad: Sequential steps as tabs */}
|
|
360
|
-
<Tab>Step 1: Info</Tab>
|
|
361
|
-
<Tab>Step 2: Payment</Tab>
|
|
362
|
-
<Tab>Step 3: Confirm</Tab>
|
|
469
|
+
### Tab Props
|
|
363
470
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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 |
|
|
369
486
|
|
|
370
|
-
|
|
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
|
+
```
|
|
371
514
|
|
|
372
515
|
## Accessibility
|
|
373
516
|
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
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
|
|
538
|
+
|
|
539
|
+
```tsx
|
|
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>
|
|
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.
|