@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.
Files changed (63) 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/SearchBar/SearchBar.d.ts +21 -0
  4. package/dist/components/SearchBar/index.d.ts +3 -0
  5. package/dist/components/data-display/DataTable.md +1 -1
  6. package/dist/components/data-display/InfoSign.md +91 -74
  7. package/dist/components/data-display/Typography.md +94 -411
  8. package/dist/components/feedback/Dialog.md +62 -76
  9. package/dist/components/feedback/Modal.md +138 -430
  10. package/dist/components/feedback/llms.txt +0 -2
  11. package/dist/components/index.d.ts +2 -1
  12. package/dist/components/inputs/Autocomplete.md +107 -356
  13. package/dist/components/inputs/ButtonGroup.md +104 -115
  14. package/dist/components/inputs/CurrencyInput.md +5 -183
  15. package/dist/components/inputs/DatePicker.md +431 -108
  16. package/dist/components/inputs/DateRangePicker.md +492 -131
  17. package/dist/components/inputs/FilterableCheckboxGroup.md +19 -145
  18. package/dist/components/inputs/IconButton.md +88 -137
  19. package/dist/components/inputs/Input.md +73 -204
  20. package/dist/components/inputs/MonthPicker.md +422 -95
  21. package/dist/components/inputs/MonthRangePicker.md +466 -89
  22. package/dist/components/inputs/PercentageInput.md +16 -185
  23. package/dist/components/inputs/RadioButton.md +35 -163
  24. package/dist/components/inputs/SearchBar.md +44 -0
  25. package/dist/components/inputs/Select.md +326 -222
  26. package/dist/components/inputs/Switch.md +376 -143
  27. package/dist/components/inputs/Textarea.md +10 -213
  28. package/dist/components/inputs/Uploader/Uploader.md +66 -145
  29. package/dist/components/inputs/llms.txt +1 -4
  30. package/dist/components/navigation/Breadcrumbs.md +308 -57
  31. package/dist/components/navigation/Drawer.md +0 -180
  32. package/dist/components/navigation/Dropdown.md +215 -98
  33. package/dist/components/navigation/IconMenuButton.md +502 -40
  34. package/dist/components/navigation/InsetDrawer.md +650 -281
  35. package/dist/components/navigation/Link.md +348 -31
  36. package/dist/components/navigation/Menu.md +285 -92
  37. package/dist/components/navigation/MenuButton.md +448 -55
  38. package/dist/components/navigation/Pagination.md +338 -47
  39. package/dist/components/navigation/Stepper.md +28 -160
  40. package/dist/components/navigation/Tabs.md +316 -57
  41. package/dist/components/surfaces/Accordions.md +804 -49
  42. package/dist/components/surfaces/Card.md +157 -97
  43. package/dist/components/surfaces/Divider.md +234 -83
  44. package/dist/components/surfaces/Sheet.md +328 -153
  45. package/dist/index.cjs +411 -574
  46. package/dist/index.d.ts +1 -1
  47. package/dist/index.js +400 -507
  48. package/dist/llms.txt +1 -9
  49. package/framer/index.js +1 -1
  50. package/package.json +17 -22
  51. package/dist/chunks/rehype-accent-FZRUD7VI.js +0 -39
  52. package/dist/components/RadioTileGroup/RadioTileGroup.d.ts +0 -56
  53. package/dist/components/RadioTileGroup/index.d.ts +0 -3
  54. package/dist/components/feedback/CircularProgress.md +0 -257
  55. package/dist/components/feedback/Skeleton.md +0 -280
  56. package/dist/components/inputs/FormControl.md +0 -361
  57. package/dist/components/inputs/RadioList.md +0 -241
  58. package/dist/components/inputs/RadioTileGroup.md +0 -507
  59. package/dist/components/inputs/Slider.md +0 -334
  60. package/dist/guides/ThemeProvider.md +0 -89
  61. package/dist/guides/llms.txt +0 -9
  62. package/dist/index.browser.js +0 -224
  63. package/dist/index.browser.js.map +0 -7
@@ -2,9 +2,7 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- The Breadcrumbs component displays a navigation trail that helps users understand their current location within a hierarchical structure and navigate back to previous levels. Each level in the path is represented as a clickable link except for the current page, which is displayed as plain text.
6
-
7
- Breadcrumbs are essential for sites with deep navigation hierarchies -- they provide context at a glance, reduce the number of steps needed to return to higher-level pages, and improve overall wayfinding within an application.
5
+ The Breadcrumbs component displays a navigation trail that helps users understand their current location within a website's hierarchy and navigate back to previous levels. It shows the path from the homepage to the current page, with each level represented as a clickable link (except for the current page). Breadcrumbs improve user experience by providing context and enabling quick navigation.
8
6
 
9
7
  ```tsx
10
8
  <Breadcrumbs
@@ -58,18 +56,26 @@ function MyComponent() {
58
56
  { label: 'Home', type: 'link', linkHref: '/' },
59
57
  { label: 'Products', type: 'link', linkHref: '/products' },
60
58
  { label: 'Electronics', type: 'link', linkHref: '/products/electronics' },
61
- { label: 'Laptops', type: 'text' },
59
+ { label: 'Laptops', type: 'text' }, // Current page (not a link)
62
60
  ];
63
61
 
64
62
  return <Breadcrumbs crumbs={crumbs} />;
65
63
  }
66
64
  ```
67
65
 
68
- ## Features
66
+ ## Examples
67
+
68
+ ### Basic Breadcrumbs
69
+
70
+ A simple breadcrumb navigation with three levels.
71
+
72
+ ```
73
+ <Canvas of={Breadcrumbs.BasicExample} />
74
+ ```
69
75
 
70
76
  ### Sizes
71
77
 
72
- Breadcrumbs are available in three sizes -- `sm`, `md`, and `lg` -- allowing you to match the surrounding layout density.
78
+ Breadcrumbs support different sizes.
73
79
 
74
80
  ```tsx
75
81
  <div>
@@ -79,9 +85,17 @@ Breadcrumbs are available in three sizes -- `sm`, `md`, and `lg` -- allowing you
79
85
  </div>
80
86
  ```
81
87
 
82
- ### Custom Separator
88
+ ### With Custom Separator
89
+
90
+ Customize the separator between breadcrumb items.
91
+
92
+ ```
93
+ <Canvas of={Breadcrumbs.CustomSeparator} />
94
+ ```
83
95
 
84
- The separator character between items can be customized via the `separator` prop. Common choices include `/`, `>`, and `-`.
96
+ ### Collapsed Breadcrumbs
97
+
98
+ For deep hierarchies, breadcrumbs can be collapsed with an ellipsis.
85
99
 
86
100
  ```tsx
87
101
  <Breadcrumbs
@@ -114,13 +128,34 @@ The separator character between items can be customized via the `separator` prop
114
128
  type: 'text'
115
129
  }]}
116
130
  collapsed
117
- separator="-"
131
+ />
132
+ ```
133
+
134
+ ### Collapsed Variants
135
+
136
+ Configure how many items show at the start and end when collapsed.
137
+
138
+ ```
139
+ <Canvas of={Breadcrumbs.CollapsedVariants} />
140
+ ```
141
+
142
+ ### Single Crumb
143
+
144
+ When there's only one item in the path.
145
+
146
+ ```tsx
147
+ <Breadcrumbs
148
+ crumbs={[{
149
+ label: 'Home',
150
+ type: 'text'
151
+ }]}
152
+ collapsed
118
153
  />
119
154
  ```
120
155
 
121
156
  ### Expanded View
122
157
 
123
- Setting `collapsed={false}` renders every item in the path without collapsing.
158
+ Show all breadcrumb items without collapsing.
124
159
 
125
160
  ```tsx
126
161
  <Breadcrumbs
@@ -156,56 +191,105 @@ Setting `collapsed={false}` renders every item in the path without collapsing.
156
191
  />
157
192
  ```
158
193
 
159
- ### Single Crumb
194
+ ## When to Use
160
195
 
161
- The component handles the edge case of a single breadcrumb item gracefully.
196
+ ### Good Use Cases
162
197
 
163
- ```tsx
164
- <Breadcrumbs
165
- crumbs={[{
166
- label: 'Home',
167
- type: 'text'
168
- }]}
169
- collapsed
170
- />
171
- ```
198
+ - **Deep hierarchies**: Sites with 3+ levels of navigation depth
199
+ - **E-commerce sites**: Product category → subcategory → product navigation
200
+ - **Documentation sites**: Section → topic → article navigation
201
+ - **File management**: Folder → subfolder → file navigation
202
+ - **Admin dashboards**: Module → submodule → detail view
203
+ - **Content management**: Categories and nested content structures
204
+
205
+ ### ❌ When Not to Use
206
+
207
+ - **Flat sites**: Single-level navigation doesn't need breadcrumbs
208
+ - **Linear flows**: For sequential processes, use Stepper instead
209
+ - **Primary navigation**: Breadcrumbs supplement, not replace, main navigation
210
+ - **Mobile-first**: Consider if space allows; may need alternative patterns
211
+ - **Dynamic content**: When paths frequently change or are user-specific
172
212
 
173
213
  ## Common Use Cases
174
214
 
175
- ### Service Detail Page
215
+ ### E-commerce Product Page
176
216
 
177
217
  ```tsx
178
- function ServiceDetailPage({ service, category }) {
218
+ function ProductPage({ product, category, subcategory }) {
179
219
  const crumbs = [
180
220
  { label: 'Home', type: 'link', linkHref: '/' },
181
- { label: 'Services', type: 'link', linkHref: '/services' },
182
- { label: category.name, type: 'link', linkHref: `/services/${category.slug}` },
183
- { label: service.name, type: 'text' },
221
+ { label: 'Shop', type: 'link', linkHref: '/shop' },
222
+ { label: category.name, type: 'link', linkHref: `/shop/${category.slug}` },
223
+ { label: subcategory.name, type: 'link', linkHref: `/shop/${category.slug}/${subcategory.slug}` },
224
+ { label: product.name, type: 'text' },
184
225
  ];
185
226
 
186
227
  return (
187
228
  <Box>
188
229
  <Breadcrumbs crumbs={crumbs} />
189
- <ServiceDetails service={service} />
230
+ <ProductDetails product={product} />
190
231
  </Box>
191
232
  );
192
233
  }
193
234
  ```
194
235
 
195
- ### Account Settings
236
+ ### Documentation Page
196
237
 
197
238
  ```tsx
198
- function AccountSettingsPage() {
239
+ function DocPage({ section, topic, article }) {
199
240
  const crumbs = [
200
- { label: 'Home', type: 'link', linkHref: '/' },
201
- { label: 'Account', type: 'link', linkHref: '/account' },
202
- { label: 'Settings', type: 'text' },
241
+ { label: 'Docs', type: 'link', linkHref: '/docs' },
242
+ { label: section.title, type: 'link', linkHref: `/docs/${section.slug}` },
243
+ { label: topic.title, type: 'link', linkHref: `/docs/${section.slug}/${topic.slug}` },
244
+ { label: article.title, type: 'text' },
203
245
  ];
204
246
 
205
247
  return (
206
- <Box>
248
+ <Stack spacing={2}>
207
249
  <Breadcrumbs crumbs={crumbs} size="sm" />
208
- <SettingsForm />
250
+ <Typography level="h1">{article.title}</Typography>
251
+ <ArticleContent content={article.content} />
252
+ </Stack>
253
+ );
254
+ }
255
+ ```
256
+
257
+ ### File Browser
258
+
259
+ ```tsx
260
+ function FileBrowser({ path }) {
261
+ const crumbs = [
262
+ { label: 'Root', type: 'link', linkHref: '/files' },
263
+ ...path.map((folder, index) => ({
264
+ label: folder.name,
265
+ type: index === path.length - 1 ? 'text' : 'link',
266
+ linkHref: `/files/${path.slice(0, index + 1).map(f => f.id).join('/')}`,
267
+ })),
268
+ ];
269
+
270
+ return (
271
+ <Box>
272
+ <Breadcrumbs crumbs={crumbs} collapsed={path.length > 4} />
273
+ <FileList folderId={path[path.length - 1].id} />
274
+ </Box>
275
+ );
276
+ }
277
+ ```
278
+
279
+ ### Admin Dashboard
280
+
281
+ ```tsx
282
+ function UserDetailPage({ user }) {
283
+ const crumbs = [
284
+ { label: 'Dashboard', type: 'link', linkHref: '/admin' },
285
+ { label: 'Users', type: 'link', linkHref: '/admin/users' },
286
+ { label: user.name, type: 'text' },
287
+ ];
288
+
289
+ return (
290
+ <Box>
291
+ <Breadcrumbs crumbs={crumbs} />
292
+ <UserProfile user={user} />
209
293
  </Box>
210
294
  );
211
295
  }
@@ -216,55 +300,222 @@ function AccountSettingsPage() {
216
300
  ```tsx
217
301
  function DynamicBreadcrumbs() {
218
302
  const location = useLocation();
219
- const pathnames = location.pathname.split('/').filter(Boolean);
303
+ const pathnames = location.pathname.split('/').filter((x) => x);
220
304
 
221
305
  const crumbs = [
222
306
  { label: 'Home', type: 'link', linkHref: '/' },
223
- ...pathnames.map((value, index) => ({
224
- label: formatLabel(value),
225
- type: index === pathnames.length - 1 ? 'text' : 'link',
226
- linkHref: `/${pathnames.slice(0, index + 1).join('/')}`,
227
- })),
307
+ ...pathnames.map((value, index) => {
308
+ const href = `/${pathnames.slice(0, index + 1).join('/')}`;
309
+ const isLast = index === pathnames.length - 1;
310
+
311
+ return {
312
+ label: formatLabel(value),
313
+ type: isLast ? 'text' : 'link',
314
+ linkHref: href,
315
+ };
316
+ }),
228
317
  ];
229
318
 
230
319
  return <Breadcrumbs crumbs={crumbs} />;
231
320
  }
232
321
  ```
233
322
 
323
+ ## Props and Customization
324
+
325
+ ### Key Props
326
+
327
+ | Prop | Type | Default | Description |
328
+ | ----------------- | ---------------------- | ------- | ----------------------------------------------- |
329
+ | `crumbs` | `Crumb[]` | `[]` | Array of breadcrumb items |
330
+ | `collapsed` | `boolean` | `true` | Collapse middle items with ellipsis |
331
+ | `startCrumbCount` | `number` | `1` | Number of items to show at start when collapsed |
332
+ | `endCrumbCount` | `number` | `3` | Number of items to show at end when collapsed |
333
+ | `separator` | `string` | `'/'` | Separator between items |
334
+ | `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Size of the breadcrumbs |
335
+
336
+ ### Crumb Type
337
+
338
+ ```tsx
339
+ interface Crumb {
340
+ label: string; // Display text
341
+ type: 'link' | 'text'; // Link or static text
342
+ linkHref?: string; // URL for link type
343
+ }
344
+ ```
345
+
346
+ ### Collapsed Behavior
347
+
348
+ When `collapsed` is true and there are more items than `startCrumbCount + endCrumbCount`, middle items are replaced with an ellipsis:
349
+
350
+ ```tsx
351
+ // With startCrumbCount=1, endCrumbCount=2, and 6 crumbs:
352
+ // Home / ... / Category / Product
353
+
354
+ <Breadcrumbs
355
+ crumbs={crumbs}
356
+ collapsed={true}
357
+ startCrumbCount={1}
358
+ endCrumbCount={2}
359
+ />
360
+ ```
361
+
362
+ ### Custom Styling
363
+
364
+ ```tsx
365
+ <Breadcrumbs
366
+ crumbs={crumbs}
367
+ sx={{
368
+ '& .MuiBreadcrumbs-separator': {
369
+ mx: 1,
370
+ color: 'neutral.400',
371
+ },
372
+ '& a': {
373
+ color: 'primary.500',
374
+ textDecoration: 'none',
375
+ '&:hover': {
376
+ textDecoration: 'underline',
377
+ },
378
+ },
379
+ }}
380
+ />
381
+ ```
382
+
383
+ ## Accessibility
384
+
385
+ Breadcrumbs include important accessibility features:
386
+
387
+ ### Semantic HTML
388
+
389
+ - Uses `<nav>` element with `aria-label="breadcrumb"`
390
+ - Structured as an ordered list (`<ol>`) to indicate sequence
391
+ - Current page marked with `aria-current="page"`
392
+
393
+ ### ARIA Attributes
394
+
395
+ ```tsx
396
+ // Generated HTML structure
397
+ <nav aria-label="breadcrumb">
398
+ <ol>
399
+ <li><a href="/">Home</a></li>
400
+ <li><a href="/products">Products</a></li>
401
+ <li aria-current="page">Current Page</li>
402
+ </ol>
403
+ </nav>
404
+ ```
405
+
406
+ ### Keyboard Navigation
407
+
408
+ - **Tab**: Navigate through breadcrumb links
409
+ - **Enter**: Activate the focused link
410
+
411
+ ### Screen Reader Support
412
+
413
+ - Screen readers announce "breadcrumb navigation"
414
+ - Each link is announced with its position in the sequence
415
+ - Current page is identified as the current location
416
+
417
+ ### SEO Benefits
418
+
419
+ Breadcrumbs provide:
420
+
421
+ - Clear site structure for search engines
422
+ - Enhanced search result display (rich snippets)
423
+ - Improved internal linking
424
+
234
425
  ## Best Practices
235
426
 
236
- - **Always start with a root item.** Begin the trail with "Home" or an equivalent top-level link so users can always navigate back to the starting point.
427
+ ### Do
428
+
429
+ 1. **Start with Home**: Always begin with a link to the homepage
237
430
 
238
431
  ```tsx
239
- // Good
432
+ // Good: Starts with Home
240
433
  const crumbs = [
241
434
  { label: 'Home', type: 'link', linkHref: '/' },
242
- { label: 'Settings', type: 'text' },
435
+ { label: 'Products', type: 'link', linkHref: '/products' },
436
+ { label: 'Laptops', type: 'text' },
243
437
  ];
244
-
245
- // Bad -- missing root item
246
- const crumbs = [{ label: 'Settings', type: 'text' }];
247
438
  ```
248
439
 
249
- - **Make the current page non-clickable.** The last item in the trail should use `type: 'text'` since clicking the current page serves no purpose.
440
+ 2. **Make current page non-clickable**: The last item should be text, not a link
250
441
 
251
442
  ```tsx
252
- // Good
443
+ // Good: Current page is text
253
444
  { label: 'Current Page', type: 'text' }
254
445
 
255
- // Bad
446
+ // Bad: Current page is a link
256
447
  { label: 'Current Page', type: 'link', linkHref: '/current' }
257
448
  ```
258
449
 
259
- - **Use collapsing for deep hierarchies.** When paths exceed four or five levels, enable `collapsed` to keep the UI clean and avoid horizontal overflow.
450
+ 3. **Use clear, concise labels**: Keep labels short but descriptive
260
451
 
261
- - **Keep labels concise.** Breadcrumb labels should be short but descriptive. Match them to the corresponding page titles for consistency.
452
+ 4. **Maintain consistency**: Use the same labels as page titles or navigation
262
453
 
263
- - **Do not use breadcrumbs as primary navigation.** They are a supplementary wayfinding aid, not a replacement for the main navigation menu.
454
+ 5. **Position at top**: Place breadcrumbs near the top of the page, below the header
264
455
 
265
- ## Accessibility
456
+ ### ❌ Don't
457
+
458
+ 1. **Don't use as primary navigation**: Breadcrumbs supplement main navigation
459
+
460
+ 2. **Don't duplicate with page title**: If the current page title is visible, breadcrumbs can end with the parent
461
+
462
+ ```tsx
463
+ // Consider ending at parent if title is displayed
464
+ const crumbs = [
465
+ { label: 'Home', type: 'link', linkHref: '/' },
466
+ { label: 'Products', type: 'link', linkHref: '/products' },
467
+ // Omit if "Laptops" is shown as page title
468
+ ];
469
+ ```
470
+
471
+ 3. **Don't use for flat navigation**: Sites with only one or two levels don't need breadcrumbs
472
+
473
+ 4. **Don't hide on mobile carelessly**: Either show a simplified version or omit entirely
474
+
475
+ ## Performance Considerations
476
+
477
+ ### Memoize Crumbs
478
+
479
+ When breadcrumbs are computed from props or state, memoize them:
480
+
481
+ ```tsx
482
+ const crumbs = useMemo(() => [
483
+ { label: 'Home', type: 'link', linkHref: '/' },
484
+ { label: category.name, type: 'link', linkHref: `/category/${category.id}` },
485
+ { label: product.name, type: 'text' },
486
+ ], [category, product]);
487
+
488
+ <Breadcrumbs crumbs={crumbs} />
489
+ ```
490
+
491
+ ### Use Collapsed for Deep Hierarchies
492
+
493
+ For paths with many levels, use collapsing to reduce DOM elements:
494
+
495
+ ```tsx
496
+ <Breadcrumbs
497
+ crumbs={deepHierarchy}
498
+ collapsed={true}
499
+ startCrumbCount={1}
500
+ endCrumbCount={2}
501
+ />
502
+ ```
503
+
504
+ ### Lazy Load for Dynamic Breadcrumbs
505
+
506
+ If breadcrumb data requires fetching, ensure it doesn't block page render:
507
+
508
+ ```tsx
509
+ function Page() {
510
+ const { data: breadcrumbData, isLoading } = useBreadcrumbPath();
511
+
512
+ return (
513
+ <Box>
514
+ {!isLoading && <Breadcrumbs crumbs={breadcrumbData} />}
515
+ <PageContent />
516
+ </Box>
517
+ );
518
+ }
519
+ ```
266
520
 
267
- - **Semantic HTML**: The component renders a `<nav>` element with `aria-label="breadcrumb"` and an ordered list (`<ol>`) to convey the sequential nature of the trail.
268
- - **Current page indicator**: The last item is automatically marked with `aria-current="page"` so screen readers announce the user's current location.
269
- - **Keyboard navigation**: All link items are focusable with `Tab` and activated with `Enter`, following standard keyboard interaction patterns.
270
- - **Screen readers**: The navigation landmark is announced as "breadcrumb navigation" and each link communicates its position within the path hierarchy.
521
+ Breadcrumbs are a simple but powerful navigation aid that helps users understand where they are and navigate efficiently. Use them consistently across your site to improve user experience and SEO.
@@ -2,10 +2,6 @@
2
2
 
3
3
  ## Introduction
4
4
 
5
- The Drawer component is a panel that slides in from the edge of the screen, overlaying the main content to present secondary information, navigation, or actions. Built on top of Joy UI's Drawer with Framer Motion animation, it provides smooth entrance and exit transitions out of the box.
6
-
7
- Drawer supports three size presets (`sm`, `md`, `lg`) which control the panel width on horizontal anchors and height on vertical anchors. On smaller viewports (below `md` breakpoint), the drawer automatically expands to full width for an optimized mobile experience.
8
-
9
5
  ```tsx
10
6
  <Drawer
11
7
  open
@@ -28,180 +24,4 @@ Drawer supports three size presets (`sm`, `md`, `lg`) which control the panel wi
28
24
 
29
25
  ```tsx
30
26
  import { Drawer } from '@ceed/cds';
31
-
32
- function MyComponent() {
33
- const [open, setOpen] = useState(false);
34
-
35
- return (
36
- <>
37
- <Button onClick={() => setOpen(true)}>Open Drawer</Button>
38
- <Drawer open={open} onClose={() => setOpen(false)}>
39
- <Box sx={{ p: 2, backgroundColor: 'white', height: '100%' }}>
40
- <Typography level="title-lg">Drawer Content</Typography>
41
- <Typography level="body-md">
42
- Place your navigation, detail view, or form content here.
43
- </Typography>
44
- </Box>
45
- </Drawer>
46
- </>
47
- );
48
- }
49
- ```
50
-
51
- ## Default
52
-
53
- The default Drawer displays a panel sliding in from the left with the `md` size preset.
54
-
55
- ```tsx
56
- <Drawer
57
- open
58
- children={<Box sx={{
59
- width: '100%',
60
- height: '100%',
61
- backgroundColor: 'white',
62
- boxShadow: 'var(--ceed-shadowRing, 0 0 #000),0px 2px 8px -2px rgba(var(--ceed-shadowChannel, 21 21 21) / var(--ceed-shadowOpacity, 0.08)),0px 6px 12px -2px rgba(var(--ceed-shadowChannel, 21 21 21) / var(--ceed-shadowOpacity, 0.08))'
63
- }}>
64
- asdas
65
- </Box>}
66
- />
67
- ```
68
-
69
- ## Common Use Cases
70
-
71
- ### Navigation Drawer
72
-
73
- ```tsx
74
- function NavigationDrawer({ open, onClose }) {
75
- const navItems = [
76
- { label: 'Home', icon: <HomeIcon />, path: '/' },
77
- { label: 'Orders', icon: <ListIcon />, path: '/orders' },
78
- { label: 'Account', icon: <PersonIcon />, path: '/account' },
79
- ];
80
-
81
- return (
82
- <Drawer open={open} onClose={onClose} size="sm">
83
- <Box sx={{ p: 2, backgroundColor: 'white', height: '100%' }}>
84
- <Typography level="title-lg" sx={{ mb: 2 }}>Menu</Typography>
85
- <List>
86
- {navItems.map((item) => (
87
- <ListItem key={item.path}>
88
- <ListItemButton onClick={() => { navigate(item.path); onClose(); }}>
89
- <ListItemDecorator>{item.icon}</ListItemDecorator>
90
- {item.label}
91
- </ListItemButton>
92
- </ListItem>
93
- ))}
94
- </List>
95
- </Box>
96
- </Drawer>
97
- );
98
- }
99
27
  ```
100
-
101
- ### Detail View
102
-
103
- ```tsx
104
- function DetailDrawer({ open, onClose, selectedItem }) {
105
- return (
106
- <Drawer open={open} onClose={onClose} anchor="right" size="lg">
107
- <Box
108
- sx={{
109
- p: 3,
110
- backgroundColor: 'white',
111
- height: '100%',
112
- display: 'flex',
113
- flexDirection: 'column',
114
- }}
115
- >
116
- <Box sx={{ display: 'flex', justifyContent: 'space-between', mb: 2 }}>
117
- <Typography level="title-lg">{selectedItem?.name}</Typography>
118
- <IconButton onClick={onClose}><CloseIcon /></IconButton>
119
- </Box>
120
- <Divider />
121
- <Box sx={{ flex: 1, overflow: 'auto', mt: 2 }}>
122
- {/* Detail content */}
123
- </Box>
124
- </Box>
125
- </Drawer>
126
- );
127
- }
128
- ```
129
-
130
- ### Form Drawer
131
-
132
- ```tsx
133
- function FormDrawer({ open, onClose, onSubmit }) {
134
- return (
135
- <Drawer open={open} onClose={onClose} anchor="right" size="md">
136
- <Box
137
- sx={{
138
- p: 3,
139
- backgroundColor: 'white',
140
- height: '100%',
141
- display: 'flex',
142
- flexDirection: 'column',
143
- }}
144
- >
145
- <Typography level="title-lg" sx={{ mb: 2 }}>Create New Item</Typography>
146
- <Divider />
147
- <Box sx={{ flex: 1, overflow: 'auto', my: 2 }}>
148
- <Stack gap={2}>
149
- <Input label="Name" placeholder="Enter name" />
150
- <Textarea label="Description" placeholder="Enter description" minRows={3} />
151
- </Stack>
152
- </Box>
153
- <Divider />
154
- <Stack direction="row" gap={1} sx={{ mt: 2, justifyContent: 'flex-end' }}>
155
- <Button variant="outlined" color="neutral" onClick={onClose}>Cancel</Button>
156
- <Button onClick={onSubmit}>Save</Button>
157
- </Stack>
158
- </Box>
159
- </Drawer>
160
- );
161
- }
162
- ```
163
-
164
- ## Best Practices
165
-
166
- 1. **Choose the right size**: Use `sm` (360px) for simple navigation, `md` (600px) for moderate content, and `lg` (900px) for complex detail views or forms.
167
-
168
- ```tsx
169
- // ✅ Good: Size matches content complexity
170
- <Drawer size="sm"> {/* Simple nav list */}
171
- <Drawer size="md"> {/* Filter panel or form */}
172
- <Drawer size="lg"> {/* Detailed information view */}
173
- ```
174
-
175
- 2. **Provide visible close affordances**: Always include a close button or cancel action inside the Drawer content, in addition to the backdrop click.
176
-
177
- ```tsx
178
- // ✅ Good: Close button inside the drawer
179
- <Drawer open={open} onClose={onClose}>
180
- <Box>
181
- <IconButton onClick={onClose}><CloseIcon /></IconButton>
182
- {/* Content */}
183
- </Box>
184
- </Drawer>
185
- ```
186
-
187
- 3. **Apply proper background and shadow styling**: The Drawer renders children directly, so you should apply background color and shadow to your content container for visual clarity.
188
-
189
- ```tsx
190
- // ✅ Good: Styled content container
191
- <Drawer open={open}>
192
- <Box sx={{ backgroundColor: 'white', height: '100%', boxShadow: 'md', p: 2 }}>
193
- {/* Content */}
194
- </Box>
195
- </Drawer>
196
- ```
197
-
198
- 4. **Do not use Drawer for confirmations**: For simple yes/no prompts, use Dialog instead. Drawer is designed for richer, scrollable content.
199
-
200
- 5. **Structure content with header, body, and footer**: Use a flex column layout to keep the header and footer fixed while allowing the body to scroll.
201
-
202
- ## Accessibility
203
-
204
- - The Drawer overlay traps focus within the panel when open, preventing keyboard users from interacting with background content.
205
- - Pressing **Escape** closes the Drawer. **Tab** and **Shift+Tab** cycle through focusable elements within the Drawer content.
206
- - On mobile viewports, the Drawer automatically expands to full width, ensuring touch targets remain accessible and content is not clipped.
207
- - Provide an `aria-label` or visible heading within the Drawer content to describe the panel's purpose for screen reader users.