@ceed/cds 1.22.2 → 1.22.4

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 (46) hide show
  1. package/dist/components/data-display/InfoSign.md +74 -91
  2. package/dist/components/data-display/Typography.md +363 -63
  3. package/dist/components/feedback/CircularProgress.md +257 -0
  4. package/dist/components/feedback/Dialog.md +8 -4
  5. package/dist/components/feedback/Modal.md +7 -3
  6. package/dist/components/feedback/Skeleton.md +280 -0
  7. package/dist/components/feedback/llms.txt +2 -0
  8. package/dist/components/inputs/ButtonGroup.md +115 -104
  9. package/dist/components/inputs/CurrencyInput.md +181 -8
  10. package/dist/components/inputs/DatePicker.md +108 -436
  11. package/dist/components/inputs/DateRangePicker.md +130 -496
  12. package/dist/components/inputs/FilterableCheckboxGroup.md +141 -20
  13. package/dist/components/inputs/FormControl.md +368 -0
  14. package/dist/components/inputs/IconButton.md +137 -88
  15. package/dist/components/inputs/Input.md +203 -77
  16. package/dist/components/inputs/MonthPicker.md +95 -427
  17. package/dist/components/inputs/MonthRangePicker.md +89 -471
  18. package/dist/components/inputs/PercentageInput.md +183 -19
  19. package/dist/components/inputs/RadioButton.md +163 -35
  20. package/dist/components/inputs/RadioList.md +241 -0
  21. package/dist/components/inputs/RadioTileGroup.md +146 -62
  22. package/dist/components/inputs/Select.md +219 -328
  23. package/dist/components/inputs/Slider.md +334 -0
  24. package/dist/components/inputs/Switch.md +143 -376
  25. package/dist/components/inputs/Textarea.md +209 -11
  26. package/dist/components/inputs/Uploader/Uploader.md +145 -66
  27. package/dist/components/inputs/llms.txt +3 -0
  28. package/dist/components/navigation/Breadcrumbs.md +57 -308
  29. package/dist/components/navigation/Drawer.md +180 -0
  30. package/dist/components/navigation/Dropdown.md +98 -215
  31. package/dist/components/navigation/IconMenuButton.md +40 -502
  32. package/dist/components/navigation/InsetDrawer.md +281 -650
  33. package/dist/components/navigation/Link.md +31 -348
  34. package/dist/components/navigation/Menu.md +92 -285
  35. package/dist/components/navigation/MenuButton.md +55 -448
  36. package/dist/components/navigation/Pagination.md +47 -338
  37. package/dist/components/navigation/Stepper.md +160 -28
  38. package/dist/components/navigation/Tabs.md +57 -316
  39. package/dist/components/surfaces/Accordions.md +49 -804
  40. package/dist/components/surfaces/Card.md +97 -157
  41. package/dist/components/surfaces/Divider.md +83 -234
  42. package/dist/components/surfaces/Sheet.md +152 -327
  43. package/dist/guides/ThemeProvider.md +89 -0
  44. package/dist/guides/llms.txt +9 -0
  45. package/dist/llms.txt +8 -0
  46. package/package.json +1 -1
@@ -2,7 +2,9 @@
2
2
 
3
3
  ## Introduction
4
4
 
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.
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.
6
8
 
7
9
  ```tsx
8
10
  <Breadcrumbs
@@ -56,26 +58,18 @@ function MyComponent() {
56
58
  { label: 'Home', type: 'link', linkHref: '/' },
57
59
  { label: 'Products', type: 'link', linkHref: '/products' },
58
60
  { label: 'Electronics', type: 'link', linkHref: '/products/electronics' },
59
- { label: 'Laptops', type: 'text' }, // Current page (not a link)
61
+ { label: 'Laptops', type: 'text' },
60
62
  ];
61
63
 
62
64
  return <Breadcrumbs crumbs={crumbs} />;
63
65
  }
64
66
  ```
65
67
 
66
- ## Examples
67
-
68
- ### Basic Breadcrumbs
69
-
70
- A simple breadcrumb navigation with three levels.
71
-
72
- ```
73
- <Canvas of={Breadcrumbs.BasicExample} />
74
- ```
68
+ ## Features
75
69
 
76
70
  ### Sizes
77
71
 
78
- Breadcrumbs support different sizes.
72
+ Breadcrumbs are available in three sizes -- `sm`, `md`, and `lg` -- allowing you to match the surrounding layout density.
79
73
 
80
74
  ```tsx
81
75
  <div>
@@ -85,17 +79,9 @@ Breadcrumbs support different sizes.
85
79
  </div>
86
80
  ```
87
81
 
88
- ### With Custom Separator
89
-
90
- Customize the separator between breadcrumb items.
91
-
92
- ```
93
- <Canvas of={Breadcrumbs.CustomSeparator} />
94
- ```
82
+ ### Custom Separator
95
83
 
96
- ### Collapsed Breadcrumbs
97
-
98
- For deep hierarchies, breadcrumbs can be collapsed with an ellipsis.
84
+ The separator character between items can be customized via the `separator` prop. Common choices include `/`, `>`, and `-`.
99
85
 
100
86
  ```tsx
101
87
  <Breadcrumbs
@@ -128,34 +114,13 @@ For deep hierarchies, breadcrumbs can be collapsed with an ellipsis.
128
114
  type: 'text'
129
115
  }]}
130
116
  collapsed
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
117
+ separator="-"
153
118
  />
154
119
  ```
155
120
 
156
121
  ### Expanded View
157
122
 
158
- Show all breadcrumb items without collapsing.
123
+ Setting `collapsed={false}` renders every item in the path without collapsing.
159
124
 
160
125
  ```tsx
161
126
  <Breadcrumbs
@@ -191,105 +156,56 @@ Show all breadcrumb items without collapsing.
191
156
  />
192
157
  ```
193
158
 
194
- ## When to Use
195
-
196
- ### ✅ Good Use Cases
197
-
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
159
+ ### Single Crumb
204
160
 
205
- ### When Not to Use
161
+ The component handles the edge case of a single breadcrumb item gracefully.
206
162
 
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
163
+ ```tsx
164
+ <Breadcrumbs
165
+ crumbs={[{
166
+ label: 'Home',
167
+ type: 'text'
168
+ }]}
169
+ collapsed
170
+ />
171
+ ```
212
172
 
213
173
  ## Common Use Cases
214
174
 
215
- ### E-commerce Product Page
175
+ ### Service Detail Page
216
176
 
217
177
  ```tsx
218
- function ProductPage({ product, category, subcategory }) {
178
+ function ServiceDetailPage({ service, category }) {
219
179
  const crumbs = [
220
180
  { label: 'Home', type: 'link', linkHref: '/' },
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' },
181
+ { label: 'Services', type: 'link', linkHref: '/services' },
182
+ { label: category.name, type: 'link', linkHref: `/services/${category.slug}` },
183
+ { label: service.name, type: 'text' },
225
184
  ];
226
185
 
227
186
  return (
228
187
  <Box>
229
188
  <Breadcrumbs crumbs={crumbs} />
230
- <ProductDetails product={product} />
231
- </Box>
232
- );
233
- }
234
- ```
235
-
236
- ### Documentation Page
237
-
238
- ```tsx
239
- function DocPage({ section, topic, article }) {
240
- const crumbs = [
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' },
245
- ];
246
-
247
- return (
248
- <Stack spacing={2}>
249
- <Breadcrumbs crumbs={crumbs} size="sm" />
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} />
189
+ <ServiceDetails service={service} />
274
190
  </Box>
275
191
  );
276
192
  }
277
193
  ```
278
194
 
279
- ### Admin Dashboard
195
+ ### Account Settings
280
196
 
281
197
  ```tsx
282
- function UserDetailPage({ user }) {
198
+ function AccountSettingsPage() {
283
199
  const crumbs = [
284
- { label: 'Dashboard', type: 'link', linkHref: '/admin' },
285
- { label: 'Users', type: 'link', linkHref: '/admin/users' },
286
- { label: user.name, type: 'text' },
200
+ { label: 'Home', type: 'link', linkHref: '/' },
201
+ { label: 'Account', type: 'link', linkHref: '/account' },
202
+ { label: 'Settings', type: 'text' },
287
203
  ];
288
204
 
289
205
  return (
290
206
  <Box>
291
- <Breadcrumbs crumbs={crumbs} />
292
- <UserProfile user={user} />
207
+ <Breadcrumbs crumbs={crumbs} size="sm" />
208
+ <SettingsForm />
293
209
  </Box>
294
210
  );
295
211
  }
@@ -300,222 +216,55 @@ function UserDetailPage({ user }) {
300
216
  ```tsx
301
217
  function DynamicBreadcrumbs() {
302
218
  const location = useLocation();
303
- const pathnames = location.pathname.split('/').filter((x) => x);
219
+ const pathnames = location.pathname.split('/').filter(Boolean);
304
220
 
305
221
  const crumbs = [
306
222
  { label: 'Home', type: 'link', linkHref: '/' },
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
- }),
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
+ })),
317
228
  ];
318
229
 
319
230
  return <Breadcrumbs crumbs={crumbs} />;
320
231
  }
321
232
  ```
322
233
 
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
-
425
234
  ## Best Practices
426
235
 
427
- ### Do
428
-
429
- 1. **Start with Home**: Always begin with a link to the homepage
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.
430
237
 
431
238
  ```tsx
432
- // Good: Starts with Home
239
+ // Good
433
240
  const crumbs = [
434
241
  { label: 'Home', type: 'link', linkHref: '/' },
435
- { label: 'Products', type: 'link', linkHref: '/products' },
436
- { label: 'Laptops', type: 'text' },
242
+ { label: 'Settings', type: 'text' },
437
243
  ];
244
+
245
+ // Bad -- missing root item
246
+ const crumbs = [{ label: 'Settings', type: 'text' }];
438
247
  ```
439
248
 
440
- 2. **Make current page non-clickable**: The last item should be text, not a link
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.
441
250
 
442
251
  ```tsx
443
- // Good: Current page is text
252
+ // Good
444
253
  { label: 'Current Page', type: 'text' }
445
254
 
446
- // Bad: Current page is a link
255
+ // Bad
447
256
  { label: 'Current Page', type: 'link', linkHref: '/current' }
448
257
  ```
449
258
 
450
- 3. **Use clear, concise labels**: Keep labels short but descriptive
451
-
452
- 4. **Maintain consistency**: Use the same labels as page titles or navigation
259
+ - **Use collapsing for deep hierarchies.** When paths exceed four or five levels, enable `collapsed` to keep the UI clean and avoid horizontal overflow.
453
260
 
454
- 5. **Position at top**: Place breadcrumbs near the top of the page, below the header
261
+ - **Keep labels concise.** Breadcrumb labels should be short but descriptive. Match them to the corresponding page titles for consistency.
455
262
 
456
- ### Don't
263
+ - **Do not use breadcrumbs as primary navigation.** They are a supplementary wayfinding aid, not a replacement for the main navigation menu.
457
264
 
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
- ```
265
+ ## Accessibility
520
266
 
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.
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.
@@ -2,6 +2,10 @@
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
+
5
9
  ```tsx
6
10
  <Drawer
7
11
  open
@@ -24,4 +28,180 @@
24
28
 
25
29
  ```tsx
26
30
  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
+ }
27
99
  ```
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.