@ceed/cds 1.28.1 → 1.29.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/SearchBar/SearchBar.d.ts +21 -0
- package/dist/components/SearchBar/index.d.ts +3 -0
- package/dist/components/data-display/DataTable.md +1 -1
- package/dist/components/data-display/InfoSign.md +91 -74
- package/dist/components/data-display/Typography.md +94 -411
- package/dist/components/feedback/Dialog.md +62 -76
- package/dist/components/feedback/Modal.md +138 -430
- package/dist/components/feedback/llms.txt +0 -2
- package/dist/components/index.d.ts +2 -1
- package/dist/components/inputs/Autocomplete.md +107 -356
- package/dist/components/inputs/ButtonGroup.md +104 -115
- 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/FilterableCheckboxGroup.md +19 -145
- package/dist/components/inputs/IconButton.md +88 -137
- package/dist/components/inputs/Input.md +73 -204
- 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/SearchBar.md +44 -0
- package/dist/components/inputs/Select.md +326 -222
- package/dist/components/inputs/Switch.md +376 -143
- package/dist/components/inputs/Textarea.md +10 -213
- package/dist/components/inputs/Uploader/Uploader.md +66 -145
- package/dist/components/inputs/llms.txt +1 -4
- package/dist/components/navigation/Breadcrumbs.md +308 -57
- package/dist/components/navigation/Drawer.md +0 -180
- package/dist/components/navigation/Dropdown.md +215 -98
- package/dist/components/navigation/IconMenuButton.md +502 -40
- package/dist/components/navigation/InsetDrawer.md +650 -281
- package/dist/components/navigation/Link.md +348 -31
- 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/Stepper.md +28 -160
- package/dist/components/navigation/Tabs.md +316 -57
- package/dist/components/surfaces/Accordions.md +804 -49
- package/dist/components/surfaces/Card.md +157 -97
- package/dist/components/surfaces/Divider.md +234 -83
- package/dist/components/surfaces/Sheet.md +328 -153
- package/dist/index.cjs +411 -574
- package/dist/index.d.ts +1 -1
- package/dist/index.js +400 -507
- package/dist/llms.txt +1 -9
- package/framer/index.js +1 -1
- package/package.json +17 -22
- package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
- package/dist/components/RadioTileGroup/RadioTileGroup.d.ts +0 -56
- package/dist/components/RadioTileGroup/index.d.ts +0 -3
- 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/RadioTileGroup.md +0 -507
- package/dist/components/inputs/Slider.md +0 -334
- package/dist/guides/ThemeProvider.md +0 -89
- package/dist/guides/llms.txt +0 -9
- package/dist/index.browser.js +0 -224
- package/dist/index.browser.js.map +0 -7
|
@@ -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
|
```
|
|
8
8
|
<Canvas of={Tabs.Playground} />
|
|
@@ -35,11 +35,11 @@ function MyComponent() {
|
|
|
35
35
|
}
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## Examples
|
|
39
39
|
|
|
40
40
|
### Basic Tabs
|
|
41
41
|
|
|
42
|
-
Default
|
|
42
|
+
Default tab navigation with horizontal layout.
|
|
43
43
|
|
|
44
44
|
```tsx
|
|
45
45
|
<Tabs {...args}>
|
|
@@ -62,7 +62,7 @@ Default horizontal tab navigation with tab panels.
|
|
|
62
62
|
|
|
63
63
|
### Variants
|
|
64
64
|
|
|
65
|
-
Tabs support
|
|
65
|
+
Tabs support different visual styles through variants.
|
|
66
66
|
|
|
67
67
|
```
|
|
68
68
|
<Canvas of={Tabs.Variants} />
|
|
@@ -70,7 +70,7 @@ Tabs support `plain`, `outlined`, `soft`, and `solid` visual styles. Apply the v
|
|
|
70
70
|
|
|
71
71
|
### Sizes
|
|
72
72
|
|
|
73
|
-
Tabs come in
|
|
73
|
+
Tabs come in different sizes to fit various use cases.
|
|
74
74
|
|
|
75
75
|
```
|
|
76
76
|
<Canvas of={Tabs.Sizes} />
|
|
@@ -78,7 +78,7 @@ Tabs come in `sm`, `md`, and `lg` sizes. Set the `size` prop on the Tabs contain
|
|
|
78
78
|
|
|
79
79
|
### Colors
|
|
80
80
|
|
|
81
|
-
Apply semantic colors
|
|
81
|
+
Apply semantic colors to tabs.
|
|
82
82
|
|
|
83
83
|
```
|
|
84
84
|
<Canvas of={Tabs.Colors} />
|
|
@@ -86,7 +86,7 @@ Apply semantic colors (`primary`, `neutral`, `success`, `warning`, `danger`) to
|
|
|
86
86
|
|
|
87
87
|
### With Decorators
|
|
88
88
|
|
|
89
|
-
Add icons or other elements
|
|
89
|
+
Add icons or other elements to tab labels.
|
|
90
90
|
|
|
91
91
|
```tsx
|
|
92
92
|
<Tabs {...args}>
|
|
@@ -109,7 +109,7 @@ Add icons or other elements before or after the tab label using `startDecorator`
|
|
|
109
109
|
|
|
110
110
|
### Vertical Orientation
|
|
111
111
|
|
|
112
|
-
|
|
112
|
+
Tabs can be arranged vertically for sidebar-style navigation.
|
|
113
113
|
|
|
114
114
|
```
|
|
115
115
|
<Canvas of={Tabs.Vertical} />
|
|
@@ -117,7 +117,7 @@ Set `orientation="vertical"` on the Tabs container for sidebar-style navigation
|
|
|
117
117
|
|
|
118
118
|
### Disabled Tabs
|
|
119
119
|
|
|
120
|
-
Individual tabs can be disabled
|
|
120
|
+
Individual tabs can be disabled while keeping others active.
|
|
121
121
|
|
|
122
122
|
```
|
|
123
123
|
<Canvas of={Tabs.Disabled} />
|
|
@@ -125,12 +125,32 @@ Individual tabs can be disabled with the `disabled` prop while keeping other tab
|
|
|
125
125
|
|
|
126
126
|
### Controlled Tabs
|
|
127
127
|
|
|
128
|
-
|
|
128
|
+
Programmatically control the active tab.
|
|
129
129
|
|
|
130
130
|
```
|
|
131
131
|
<Canvas of={Tabs.Controlled} />
|
|
132
132
|
```
|
|
133
133
|
|
|
134
|
+
## When to Use
|
|
135
|
+
|
|
136
|
+
### ✅ Good Use Cases
|
|
137
|
+
|
|
138
|
+
- **Related content sections**: When content can be logically grouped and users don't need to see all sections at once
|
|
139
|
+
- **Settings pages**: Organizing different categories of settings (Profile, Security, Notifications)
|
|
140
|
+
- **Dashboard views**: Switching between different data views or time periods
|
|
141
|
+
- **Product details**: Showing Description, Specifications, Reviews as separate tabs
|
|
142
|
+
- **Form sections**: Breaking long forms into logical steps (not for strict wizard flows)
|
|
143
|
+
- **Code examples**: Showing code in different languages or frameworks
|
|
144
|
+
|
|
145
|
+
### ❌ When Not to Use
|
|
146
|
+
|
|
147
|
+
- **Primary navigation**: Use a navigation menu or sidebar for main app navigation
|
|
148
|
+
- **Sequential workflows**: Use Stepper for multi-step processes that must be completed in order
|
|
149
|
+
- **Comparing content**: If users need to see multiple sections simultaneously, use accordions or show all content
|
|
150
|
+
- **Very few items**: If there are only 2 options, consider using a toggle or radio buttons
|
|
151
|
+
- **Many items**: More than 5-6 tabs become hard to navigate; consider a dropdown or nested navigation
|
|
152
|
+
- **Mobile layouts**: Consider alternative patterns like accordions or stacked sections on small screens
|
|
153
|
+
|
|
134
154
|
## Common Use Cases
|
|
135
155
|
|
|
136
156
|
### Settings Page
|
|
@@ -143,92 +163,331 @@ function SettingsPage() {
|
|
|
143
163
|
<Tab startDecorator={<PersonIcon />}>Profile</Tab>
|
|
144
164
|
<Tab startDecorator={<SecurityIcon />}>Security</Tab>
|
|
145
165
|
<Tab startDecorator={<NotificationsIcon />}>Notifications</Tab>
|
|
166
|
+
<Tab startDecorator={<PaletteIcon />}>Appearance</Tab>
|
|
167
|
+
</TabList>
|
|
168
|
+
<TabPanel value={0}>
|
|
169
|
+
<ProfileSettings />
|
|
170
|
+
</TabPanel>
|
|
171
|
+
<TabPanel value={1}>
|
|
172
|
+
<SecuritySettings />
|
|
173
|
+
</TabPanel>
|
|
174
|
+
<TabPanel value={2}>
|
|
175
|
+
<NotificationSettings />
|
|
176
|
+
</TabPanel>
|
|
177
|
+
<TabPanel value={3}>
|
|
178
|
+
<AppearanceSettings />
|
|
179
|
+
</TabPanel>
|
|
180
|
+
</Tabs>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Product Detail Page
|
|
186
|
+
|
|
187
|
+
```tsx
|
|
188
|
+
function ProductDetails({ product }) {
|
|
189
|
+
return (
|
|
190
|
+
<Tabs defaultValue={0}>
|
|
191
|
+
<TabList>
|
|
192
|
+
<Tab>Description</Tab>
|
|
193
|
+
<Tab>Specifications</Tab>
|
|
194
|
+
<Tab>Reviews ({product.reviewCount})</Tab>
|
|
195
|
+
<Tab>Q&A</Tab>
|
|
146
196
|
</TabList>
|
|
147
|
-
<TabPanel value={0}
|
|
148
|
-
|
|
149
|
-
|
|
197
|
+
<TabPanel value={0}>
|
|
198
|
+
<Typography>{product.description}</Typography>
|
|
199
|
+
</TabPanel>
|
|
200
|
+
<TabPanel value={1}>
|
|
201
|
+
<SpecificationTable specs={product.specifications} />
|
|
202
|
+
</TabPanel>
|
|
203
|
+
<TabPanel value={2}>
|
|
204
|
+
<ReviewList reviews={product.reviews} />
|
|
205
|
+
</TabPanel>
|
|
206
|
+
<TabPanel value={3}>
|
|
207
|
+
<QASection productId={product.id} />
|
|
208
|
+
</TabPanel>
|
|
150
209
|
</Tabs>
|
|
151
210
|
);
|
|
152
211
|
}
|
|
153
212
|
```
|
|
154
213
|
|
|
155
|
-
### Dashboard Time
|
|
214
|
+
### Dashboard with Time Filters
|
|
156
215
|
|
|
157
216
|
```tsx
|
|
158
217
|
function DashboardTabs() {
|
|
159
|
-
const [
|
|
218
|
+
const [timeRange, setTimeRange] = useState('week');
|
|
160
219
|
|
|
161
220
|
return (
|
|
162
|
-
<Tabs value={
|
|
221
|
+
<Tabs value={timeRange} onChange={(e, val) => setTimeRange(val as string)}>
|
|
163
222
|
<TabList>
|
|
164
223
|
<Tab value="day">Today</Tab>
|
|
165
224
|
<Tab value="week">This Week</Tab>
|
|
166
225
|
<Tab value="month">This Month</Tab>
|
|
226
|
+
<Tab value="year">This Year</Tab>
|
|
167
227
|
</TabList>
|
|
168
|
-
<TabPanel value="day"
|
|
169
|
-
|
|
170
|
-
|
|
228
|
+
<TabPanel value="day">
|
|
229
|
+
<DailyStats />
|
|
230
|
+
</TabPanel>
|
|
231
|
+
<TabPanel value="week">
|
|
232
|
+
<WeeklyStats />
|
|
233
|
+
</TabPanel>
|
|
234
|
+
<TabPanel value="month">
|
|
235
|
+
<MonthlyStats />
|
|
236
|
+
</TabPanel>
|
|
237
|
+
<TabPanel value="year">
|
|
238
|
+
<YearlyStats />
|
|
239
|
+
</TabPanel>
|
|
171
240
|
</Tabs>
|
|
172
241
|
);
|
|
173
242
|
}
|
|
174
243
|
```
|
|
175
244
|
|
|
176
|
-
###
|
|
245
|
+
### Code Examples
|
|
177
246
|
|
|
178
247
|
```tsx
|
|
179
|
-
function
|
|
248
|
+
function CodeExamples() {
|
|
180
249
|
return (
|
|
181
|
-
<Tabs
|
|
250
|
+
<Tabs defaultValue="react">
|
|
182
251
|
<TabList>
|
|
183
|
-
<Tab
|
|
184
|
-
<Tab
|
|
185
|
-
<Tab
|
|
252
|
+
<Tab value="react">React</Tab>
|
|
253
|
+
<Tab value="vue">Vue</Tab>
|
|
254
|
+
<Tab value="angular">Angular</Tab>
|
|
186
255
|
</TabList>
|
|
187
|
-
<TabPanel value=
|
|
188
|
-
|
|
189
|
-
|
|
256
|
+
<TabPanel value="react">
|
|
257
|
+
<CodeBlock language="jsx">{reactCode}</CodeBlock>
|
|
258
|
+
</TabPanel>
|
|
259
|
+
<TabPanel value="vue">
|
|
260
|
+
<CodeBlock language="vue">{vueCode}</CodeBlock>
|
|
261
|
+
</TabPanel>
|
|
262
|
+
<TabPanel value="angular">
|
|
263
|
+
<CodeBlock language="typescript">{angularCode}</CodeBlock>
|
|
264
|
+
</TabPanel>
|
|
190
265
|
</Tabs>
|
|
191
266
|
);
|
|
192
267
|
}
|
|
193
268
|
```
|
|
194
269
|
|
|
195
|
-
|
|
270
|
+
### Vertical Sidebar Navigation
|
|
196
271
|
|
|
197
|
-
|
|
272
|
+
```tsx
|
|
273
|
+
function SidebarTabs() {
|
|
274
|
+
return (
|
|
275
|
+
<Box sx={{ display: 'flex' }}>
|
|
276
|
+
<Tabs orientation="vertical" defaultValue={0} sx={{ minWidth: 200 }}>
|
|
277
|
+
<TabList>
|
|
278
|
+
<Tab startDecorator={<DashboardIcon />}>Dashboard</Tab>
|
|
279
|
+
<Tab startDecorator={<AnalyticsIcon />}>Analytics</Tab>
|
|
280
|
+
<Tab startDecorator={<ReportsIcon />}>Reports</Tab>
|
|
281
|
+
<Tab startDecorator={<SettingsIcon />}>Settings</Tab>
|
|
282
|
+
</TabList>
|
|
283
|
+
</Tabs>
|
|
284
|
+
<Box sx={{ flex: 1, p: 2 }}>
|
|
285
|
+
<TabPanel value={0}>Dashboard content</TabPanel>
|
|
286
|
+
<TabPanel value={1}>Analytics content</TabPanel>
|
|
287
|
+
<TabPanel value={2}>Reports content</TabPanel>
|
|
288
|
+
<TabPanel value={3}>Settings content</TabPanel>
|
|
289
|
+
</Box>
|
|
290
|
+
</Box>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
```
|
|
198
294
|
|
|
199
|
-
|
|
200
|
-
{/* ✅ Good: Descriptive labels */}
|
|
201
|
-
<Tab>Account Settings</Tab>
|
|
202
|
-
<Tab>Notifications</Tab>
|
|
295
|
+
## Component Structure
|
|
203
296
|
|
|
204
|
-
|
|
205
|
-
<Tab>Tab 1</Tab>
|
|
206
|
-
<Tab>Other</Tab>
|
|
207
|
-
```
|
|
297
|
+
Tabs uses a composition pattern with multiple sub-components:
|
|
208
298
|
|
|
209
|
-
|
|
299
|
+
```tsx
|
|
300
|
+
<Tabs> {/* Container - manages state */}
|
|
301
|
+
<TabList> {/* Tab button container */}
|
|
302
|
+
<Tab>Tab 1</Tab> {/* Individual tab buttons */}
|
|
303
|
+
<Tab>Tab 2</Tab>
|
|
304
|
+
</TabList>
|
|
305
|
+
<TabPanel value={0}> {/* Content panels */}
|
|
306
|
+
Content 1
|
|
307
|
+
</TabPanel>
|
|
308
|
+
<TabPanel value={1}>
|
|
309
|
+
Content 2
|
|
310
|
+
</TabPanel>
|
|
311
|
+
</Tabs>
|
|
312
|
+
```
|
|
210
313
|
|
|
211
|
-
|
|
314
|
+
## Props and Customization
|
|
212
315
|
|
|
213
|
-
|
|
316
|
+
### Tabs Props
|
|
214
317
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
318
|
+
| Prop | Type | Default | Description |
|
|
319
|
+
| -------------- | ---------------------------- | -------------- | ----------------------------------- |
|
|
320
|
+
| `defaultValue` | `string \| number` | - | Default selected tab (uncontrolled) |
|
|
321
|
+
| `value` | `string \| number` | - | Selected tab (controlled) |
|
|
322
|
+
| `onChange` | `function` | - | Callback when tab changes |
|
|
323
|
+
| `orientation` | `'horizontal' \| 'vertical'` | `'horizontal'` | Tab layout direction |
|
|
324
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of all child components |
|
|
220
325
|
|
|
221
|
-
|
|
222
|
-
<Tab>Profile</Tab>
|
|
223
|
-
<Tab>Security</Tab>
|
|
224
|
-
<Tab>Billing</Tab>
|
|
225
|
-
```
|
|
326
|
+
### Tab Props
|
|
226
327
|
|
|
227
|
-
|
|
328
|
+
| Prop | Type | Default | Description |
|
|
329
|
+
| ---------------- | -------------------------------------------------------------- | --------- | ---------------------------------- |
|
|
330
|
+
| `value` | `string \| number` | - | Tab identifier (defaults to index) |
|
|
331
|
+
| `variant` | `'plain' \| 'outlined' \| 'soft' \| 'solid'` | `'plain'` | Visual style |
|
|
332
|
+
| `color` | `'primary' \| 'neutral' \| 'danger' \| 'success' \| 'warning'` | - | Color scheme |
|
|
333
|
+
| `disabled` | `boolean` | `false` | Disable the tab |
|
|
334
|
+
| `startDecorator` | `ReactNode` | - | Element before tab label |
|
|
335
|
+
| `endDecorator` | `ReactNode` | - | Element after tab label |
|
|
336
|
+
|
|
337
|
+
### TabPanel Props
|
|
338
|
+
|
|
339
|
+
| Prop | Type | Default | Description |
|
|
340
|
+
| ------------- | ------------------ | ------- | ----------------------------- |
|
|
341
|
+
| `value` | `string \| number` | - | Matching tab value |
|
|
342
|
+
| `keepMounted` | `boolean` | `false` | Keep panel in DOM when hidden |
|
|
343
|
+
|
|
344
|
+
### Custom Styling
|
|
345
|
+
|
|
346
|
+
```tsx
|
|
347
|
+
<Tabs
|
|
348
|
+
sx={{
|
|
349
|
+
'--Tabs-gap': '8px',
|
|
350
|
+
}}
|
|
351
|
+
>
|
|
352
|
+
<TabList
|
|
353
|
+
sx={{
|
|
354
|
+
borderBottom: '1px solid',
|
|
355
|
+
borderColor: 'divider',
|
|
356
|
+
}}
|
|
357
|
+
>
|
|
358
|
+
<Tab
|
|
359
|
+
sx={{
|
|
360
|
+
'&.Mui-selected': {
|
|
361
|
+
borderBottom: '2px solid',
|
|
362
|
+
borderColor: 'primary.500',
|
|
363
|
+
},
|
|
364
|
+
}}
|
|
365
|
+
>
|
|
366
|
+
Custom Tab
|
|
367
|
+
</Tab>
|
|
368
|
+
</TabList>
|
|
369
|
+
</Tabs>
|
|
370
|
+
```
|
|
228
371
|
|
|
229
372
|
## Accessibility
|
|
230
373
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
374
|
+
Tabs components follow WAI-ARIA Tabs pattern for comprehensive accessibility:
|
|
375
|
+
|
|
376
|
+
### ARIA Attributes
|
|
377
|
+
|
|
378
|
+
- `role="tablist"` on TabList
|
|
379
|
+
- `role="tab"` on each Tab
|
|
380
|
+
- `role="tabpanel"` on each TabPanel
|
|
381
|
+
- `aria-selected` indicates the active tab
|
|
382
|
+
- `aria-controls` links tabs to their panels
|
|
383
|
+
- `aria-labelledby` links panels to their tabs
|
|
384
|
+
|
|
385
|
+
### Keyboard Navigation
|
|
386
|
+
|
|
387
|
+
- **Tab**: Move focus to the tab list, then to the active panel
|
|
388
|
+
- **Arrow Left/Right**: Move between tabs (horizontal orientation)
|
|
389
|
+
- **Arrow Up/Down**: Move between tabs (vertical orientation)
|
|
390
|
+
- **Home**: Move to first tab
|
|
391
|
+
- **End**: Move to last tab
|
|
392
|
+
- **Enter/Space**: Activate the focused tab
|
|
393
|
+
|
|
394
|
+
### Screen Reader Support
|
|
395
|
+
|
|
396
|
+
```tsx
|
|
397
|
+
<Tabs aria-label="Account settings tabs">
|
|
398
|
+
<TabList>
|
|
399
|
+
<Tab>Profile</Tab>
|
|
400
|
+
<Tab>Security</Tab>
|
|
401
|
+
</TabList>
|
|
402
|
+
<TabPanel value={0}>
|
|
403
|
+
<h2 id="profile-heading">Profile Settings</h2>
|
|
404
|
+
{/* Content */}
|
|
405
|
+
</TabPanel>
|
|
406
|
+
</Tabs>
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## Best Practices
|
|
410
|
+
|
|
411
|
+
### ✅ Do
|
|
412
|
+
|
|
413
|
+
1. **Use clear, concise labels**: Tab labels should clearly describe the content
|
|
414
|
+
|
|
415
|
+
```tsx
|
|
416
|
+
// ✅ Good: Clear labels
|
|
417
|
+
<Tab>Account Settings</Tab>
|
|
418
|
+
<Tab>Notifications</Tab>
|
|
419
|
+
|
|
420
|
+
// ❌ Bad: Vague labels
|
|
421
|
+
<Tab>Tab 1</Tab>
|
|
422
|
+
<Tab>Other</Tab>
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
2. **Keep tab count manageable**: Limit to 5-6 tabs maximum
|
|
426
|
+
|
|
427
|
+
3. **Order tabs logically**: Place most important or frequently used tabs first
|
|
428
|
+
|
|
429
|
+
4. **Use consistent styling**: All tabs should have the same visual weight
|
|
430
|
+
|
|
431
|
+
5. **Show active state clearly**: Users should always know which tab is selected
|
|
432
|
+
|
|
433
|
+
### ❌ Don't
|
|
434
|
+
|
|
435
|
+
1. **Don't hide critical information**: Important content shouldn't be buried in secondary tabs
|
|
436
|
+
|
|
437
|
+
2. **Don't use for sequential processes**: Use Stepper for ordered workflows
|
|
438
|
+
|
|
439
|
+
```tsx
|
|
440
|
+
// ❌ Bad: Sequential steps as tabs
|
|
441
|
+
<Tab>Step 1: Personal Info</Tab>
|
|
442
|
+
<Tab>Step 2: Payment</Tab>
|
|
443
|
+
<Tab>Step 3: Confirm</Tab>
|
|
444
|
+
|
|
445
|
+
// ✅ Good: Use Stepper instead
|
|
446
|
+
<Stepper activeStep={activeStep}>
|
|
447
|
+
<Step>Personal Info</Step>
|
|
448
|
+
<Step>Payment</Step>
|
|
449
|
+
<Step>Confirm</Step>
|
|
450
|
+
</Stepper>
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
3. **Don't nest tabs within tabs**: Creates confusing navigation
|
|
454
|
+
|
|
455
|
+
4. **Don't use inconsistent tab counts**: If tabs are dynamic, consider alternative UI patterns
|
|
456
|
+
|
|
457
|
+
## Performance Considerations
|
|
458
|
+
|
|
459
|
+
### Lazy Loading Tab Content
|
|
460
|
+
|
|
461
|
+
By default, inactive tab panels are not rendered. For complex content, this provides automatic lazy loading:
|
|
462
|
+
|
|
463
|
+
```tsx
|
|
464
|
+
<TabPanel value={0}>
|
|
465
|
+
{/* Only rendered when this tab is active */}
|
|
466
|
+
<HeavyComponent />
|
|
467
|
+
</TabPanel>
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
### Keep Mounted
|
|
471
|
+
|
|
472
|
+
Use `keepMounted` when tab content needs to maintain state:
|
|
473
|
+
|
|
474
|
+
```tsx
|
|
475
|
+
<TabPanel value={0} keepMounted>
|
|
476
|
+
{/* Stays in DOM, maintains form state */}
|
|
477
|
+
<FormWithState />
|
|
478
|
+
</TabPanel>
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Avoid Heavy Re-renders
|
|
482
|
+
|
|
483
|
+
Memoize tab content when it depends on complex calculations:
|
|
484
|
+
|
|
485
|
+
```tsx
|
|
486
|
+
const tabContent = useMemo(() => (
|
|
487
|
+
<ExpensiveComponent data={data} />
|
|
488
|
+
), [data]);
|
|
489
|
+
|
|
490
|
+
<TabPanel value={0}>{tabContent}</TabPanel>
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
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.
|