@ceed/ads 1.29.0 → 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.
Files changed (64) hide show
  1. package/dist/components/CurrencyInput/CurrencyInput.d.ts +1 -1
  2. package/dist/components/CurrencyInput/hooks/use-currency-setting.d.ts +2 -2
  3. package/dist/components/DataTable/hooks.d.ts +2 -1
  4. package/dist/components/DataTable/utils.d.ts +1 -0
  5. package/dist/components/ProfileMenu/ProfileMenu.d.ts +1 -1
  6. package/dist/components/SearchBar/SearchBar.d.ts +21 -0
  7. package/dist/components/SearchBar/index.d.ts +3 -0
  8. package/dist/components/data-display/Badge.md +39 -71
  9. package/dist/components/data-display/DataTable.md +1 -1
  10. package/dist/components/data-display/InfoSign.md +98 -74
  11. package/dist/components/data-display/Typography.md +97 -363
  12. package/dist/components/feedback/Dialog.md +62 -76
  13. package/dist/components/feedback/Modal.md +44 -259
  14. package/dist/components/feedback/llms.txt +0 -2
  15. package/dist/components/index.d.ts +2 -0
  16. package/dist/components/inputs/Autocomplete.md +107 -356
  17. package/dist/components/inputs/ButtonGroup.md +106 -115
  18. package/dist/components/inputs/Calendar.md +459 -98
  19. package/dist/components/inputs/CurrencyInput.md +5 -183
  20. package/dist/components/inputs/DatePicker.md +431 -108
  21. package/dist/components/inputs/DateRangePicker.md +492 -131
  22. package/dist/components/inputs/FilterMenu.md +19 -169
  23. package/dist/components/inputs/FilterableCheckboxGroup.md +23 -123
  24. package/dist/components/inputs/IconButton.md +88 -137
  25. package/dist/components/inputs/Input.md +0 -5
  26. package/dist/components/inputs/MonthPicker.md +422 -95
  27. package/dist/components/inputs/MonthRangePicker.md +466 -89
  28. package/dist/components/inputs/PercentageInput.md +16 -185
  29. package/dist/components/inputs/RadioButton.md +35 -163
  30. package/dist/components/inputs/RadioTileGroup.md +61 -150
  31. package/dist/components/inputs/SearchBar.md +44 -0
  32. package/dist/components/inputs/Select.md +326 -222
  33. package/dist/components/inputs/Switch.md +376 -136
  34. package/dist/components/inputs/Textarea.md +10 -213
  35. package/dist/components/inputs/Uploader/Uploader.md +66 -145
  36. package/dist/components/inputs/llms.txt +1 -3
  37. package/dist/components/navigation/Breadcrumbs.md +322 -80
  38. package/dist/components/navigation/Dropdown.md +221 -92
  39. package/dist/components/navigation/IconMenuButton.md +502 -40
  40. package/dist/components/navigation/InsetDrawer.md +738 -68
  41. package/dist/components/navigation/Link.md +298 -39
  42. package/dist/components/navigation/Menu.md +285 -92
  43. package/dist/components/navigation/MenuButton.md +448 -55
  44. package/dist/components/navigation/Pagination.md +338 -47
  45. package/dist/components/navigation/ProfileMenu.md +268 -45
  46. package/dist/components/navigation/Stepper.md +28 -160
  47. package/dist/components/navigation/Tabs.md +316 -57
  48. package/dist/components/surfaces/Sheet.md +334 -151
  49. package/dist/index.browser.js +15 -13
  50. package/dist/index.browser.js.map +4 -4
  51. package/dist/index.cjs +313 -291
  52. package/dist/index.d.ts +1 -1
  53. package/dist/index.js +450 -372
  54. package/dist/llms.txt +1 -8
  55. package/framer/index.js +1 -1
  56. package/package.json +16 -15
  57. package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
  58. package/dist/components/feedback/CircularProgress.md +0 -257
  59. package/dist/components/feedback/Skeleton.md +0 -280
  60. package/dist/components/inputs/FormControl.md +0 -361
  61. package/dist/components/inputs/RadioList.md +0 -241
  62. package/dist/components/inputs/Slider.md +0 -334
  63. package/dist/guides/ThemeProvider.md +0 -116
  64. package/dist/guides/llms.txt +0 -9
@@ -1,8 +1,8 @@
1
1
  # Tabs
2
2
 
3
- Tabs organize content into separate views where only one view is visible at a time. Users switch between views by selecting tab buttons, enabling efficient navigation within related content sections without leaving the current page. Built on Joy UI's Tabs, TabList, Tab, and TabPanel components, Tabs support horizontal and vertical orientations, multiple visual variants, semantic colors, and icon decorators.
3
+ ## Introduction
4
4
 
5
- Tabs follow a composition pattern: the `Tabs` container manages state, `TabList` holds the tab buttons, `Tab` is each individual button, and `TabPanel` displays the content for the active tab.
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
- ## Features
53
+ ## Examples
54
54
 
55
55
  ### Basic Tabs
56
56
 
57
- Default horizontal tab navigation with tab panels.
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 `plain`, `outlined`, `soft`, and `solid` visual styles. Apply the variant to both TabList and individual Tab components for a consistent appearance.
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 `sm`, `md`, and `lg` sizes. Set the `size` prop on the Tabs container to affect all child components uniformly.
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 (`primary`, `neutral`, `success`, `warning`, `danger`) to individual tabs for color-coded navigation.
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 before or after the tab label using `startDecorator` and `endDecorator` props.
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
- Set `orientation="vertical"` on the Tabs container for sidebar-style navigation layouts.
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 with the `disabled` prop while keeping other tabs interactive.
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
- Use the `value` and `onChange` props for programmatic control of the active tab.
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}><ProfileSettings /></TabPanel>
291
- <TabPanel value={1}><SecuritySettings /></TabPanel>
292
- <TabPanel value={2}><NotificationSettings /></TabPanel>
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 Range
357
+ ### Dashboard with Time Filters
299
358
 
300
359
  ```tsx
301
360
  function DashboardTabs() {
302
- const [range, setRange] = useState('week');
361
+ const [timeRange, setTimeRange] = useState('week');
303
362
 
304
363
  return (
305
- <Tabs value={range} onChange={(e, val) => setRange(val as string)}>
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"><DailyStats /></TabPanel>
312
- <TabPanel value="week"><WeeklyStats /></TabPanel>
313
- <TabPanel value="month"><MonthlyStats /></TabPanel>
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
- ### Vertical Sidebar
388
+ ### Code Examples
320
389
 
321
390
  ```tsx
322
- function SidebarTabs() {
391
+ function CodeExamples() {
323
392
  return (
324
- <Tabs orientation="vertical" defaultValue={0} sx={{ minWidth: 300 }}>
393
+ <Tabs defaultValue="react">
325
394
  <TabList>
326
- <Tab startDecorator={<DashboardIcon />}>Dashboard</Tab>
327
- <Tab startDecorator={<AnalyticsIcon />}>Analytics</Tab>
328
- <Tab startDecorator={<SettingsIcon />}>Settings</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={0}>Dashboard content</TabPanel>
331
- <TabPanel value={1}>Analytics content</TabPanel>
332
- <TabPanel value={2}>Settings content</TabPanel>
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
- ## Best Practices
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
- - **Use clear, concise tab labels.** Each label should describe the content it reveals. Avoid generic names like "Tab 1" or "Other".
438
+ ## Component Structure
341
439
 
342
- ```tsx
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
- {/* ❌ Bad: Vague labels */}
348
- <Tab>Tab 1</Tab>
349
- <Tab>Other</Tab>
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
- - **Limit the number of tabs.** Aim for 3-6 tabs. More than 6 tabs become difficult to scan and navigate. If you need more sections, consider a sidebar navigation, nested navigation, or a different layout pattern.
457
+ ## Props and Customization
353
458
 
354
- - **Order tabs by importance.** Place the most frequently used or most important tab first. Users expect the default (leftmost or topmost) tab to contain the primary content.
459
+ ### Tabs Props
355
460
 
356
- - **Do not use Tabs for sequential workflows.** Tabs are for parallel content sections that can be accessed in any order. For ordered multi-step processes, use a Stepper component instead.
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
- ```tsx
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
- {/* Good: Independent content sections */}
365
- <Tab>Profile</Tab>
366
- <Tab>Security</Tab>
367
- <Tab>Billing</Tab>
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
- - **Keep styling consistent.** All tabs in a group should share the same variant and color. Mixing styles within the same TabList creates visual inconsistency.
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
- - **WAI-ARIA Tabs pattern**: TabList receives `role="tablist"`, each Tab receives `role="tab"`, and each TabPanel receives `role="tabpanel"`. The `aria-selected`, `aria-controls`, and `aria-labelledby` attributes are set automatically.
375
- - **Keyboard navigation**: Arrow Left/Right moves between tabs in horizontal orientation. Arrow Up/Down moves between tabs in vertical orientation. Home jumps to the first tab, End to the last. Enter or Space activates the focused tab.
376
- - **Tab key behavior**: Pressing Tab from outside the tab list focuses the active tab. Pressing Tab again moves focus into the active panel content, not to the next tab button.
377
- - **Provide an accessible label**: Use `aria-label` on the Tabs container to give screen readers context for the tab group (e.g., `aria-label="Account settings"`).
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.