@bento/listbox 0.1.2 → 0.2.0

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/README.md ADDED
@@ -0,0 +1,540 @@
1
+ # ListBox
2
+
3
+ The `@bento/listbox` package provides a flexible, accessible listbox primitive that supports both controlled and uncontrolled selection modes. Built on React Aria for interaction fidelity and designed for composition within higher-level components like Select, Combobox, and Menu.
4
+
5
+ ## Installation
6
+
7
+ ```shell
8
+ npm install --save @bento/listbox
9
+ ```
10
+
11
+ ## Component Structure
12
+
13
+ The `@bento/listbox` package exports five main components:
14
+
15
+ - **ListBox**: The main container component that manages selection state, keyboard navigation, and accessibility
16
+ - **ListBoxItem**: Individual selectable items within the listbox
17
+ - **ListBoxSection**: Optional grouping component for organizing options into sections
18
+ - **Header**: Accessible heading for a `ListBoxSection`, forwards props and refs for full styling control
19
+ - **Collection**: Utility for rendering nested dynamic data inside a `ListBoxSection` (or other collection-aware context).
20
+
21
+ ## Props
22
+
23
+ The following properties are available on the `ListBox` component:
24
+
25
+ ## Static Items
26
+
27
+ ```tsx
28
+ /* v8 ignore next */
29
+ import React from 'react';
30
+ import { ListBox, ListBoxItem } from '@bento/listbox';
31
+ import style from './listbox.module.css';
32
+
33
+ /**
34
+ * Example component demonstrating basic ListBox usage.
35
+ *
36
+ * @param {any} args - The component props.
37
+ * @returns {JSX.Element} The rendered ListBox with static items.
38
+ * @public
39
+ */
40
+ export function BasicListBoxExample(args: any) {
41
+ return (
42
+ <ListBox {...args} className={style.listbox}>
43
+ <ListBoxItem>Chicken Teriyaki</ListBoxItem>
44
+ <ListBoxItem>Salmon Bento</ListBoxItem>
45
+ <ListBoxItem>Beef Bowl</ListBoxItem>
46
+ </ListBox>
47
+ );
48
+ }
49
+ ```
50
+
51
+ ## Sections
52
+
53
+ Use `ListBoxSection` to group related options. Use `Header` inside a `ListBoxSection` to render an accessible heading for the group. It automatically links the heading to the section via `aria-labelledby`.
54
+
55
+ The `<Header>` component accepts standard DOM props and a `slot` prop for Bento’s slot system, enabling fine-grained overrides in composite components.
56
+
57
+ ```tsx
58
+ /* v8 ignore next */
59
+ import React from 'react';
60
+ import { ListBox, ListBoxItem, ListBoxSection, Header } from '@bento/listbox';
61
+ import style from './listbox.module.css';
62
+
63
+ /**
64
+ * Example component demonstrating ListBox with static sections.
65
+ *
66
+ * @param {any} args - The component props.
67
+ * @returns {JSX.Element} The rendered ListBox with sectioned items.
68
+ * @public
69
+ */
70
+ export function SectionsExample(args: any) {
71
+ return (
72
+ <ListBox {...args} className={style.listbox}>
73
+ <ListBoxSection>
74
+ <Header>Main Dishes</Header>
75
+ <ListBoxItem>Chicken Teriyaki</ListBoxItem>
76
+ <ListBoxItem>Salmon Bento</ListBoxItem>
77
+ </ListBoxSection>
78
+ <ListBoxSection>
79
+ <Header>Side Dishes</Header>
80
+ <ListBoxItem>Pickled Vegetables</ListBoxItem>
81
+ <ListBoxItem>Edamame</ListBoxItem>
82
+ </ListBoxSection>
83
+ </ListBox>
84
+ );
85
+ }
86
+ ```
87
+
88
+ ## Dynamic Collections
89
+
90
+ For dynamic data, use the `items` prop with a render function. The ListBox component follows different patterns depending on how it's used:
91
+
92
+ ### When `items` prop is provided
93
+ When you provide an `items` prop, the `children` function receives **individual items** for React Aria compatibility:
94
+
95
+ ```tsx
96
+ /* v8 ignore next */
97
+ import React from 'react';
98
+ import { ListBox, ListBoxItem } from '@bento/listbox';
99
+ import style from './listbox.module.css';
100
+
101
+ /**
102
+ * Example component demonstrating ListBox with dynamic collections.
103
+ *
104
+ * @param {any} args - The component props including items array.
105
+ * @returns {JSX.Element} The rendered ListBox with dynamic items.
106
+ * @public
107
+ */
108
+ export function DynamicCollectionExample({ items, ...args }: any) {
109
+ return (
110
+ <ListBox {...args} className={style.listbox} items={items}>
111
+ {(item: any) => (
112
+ <ListBoxItem key={item.id} textValue={item.name}>
113
+ {item.name}
114
+ </ListBoxItem>
115
+ )}
116
+ </ListBox>
117
+ );
118
+ }
119
+ ```
120
+
121
+ In this pattern, `children` is called for each item in the `items` array, receiving the individual item data to render `ListBoxItem` components.
122
+
123
+ ### When no `items` prop is provided
124
+ When you don't provide an `items` prop but use `children` as a function, it follows **Bento's render prop pattern** and receives an object with render props:
125
+
126
+ ```tsx
127
+ <ListBox aria-label="Custom ListBox">
128
+ {({ isEmpty, isFocused, state, items }) => (
129
+ isEmpty ? (
130
+ <div>No items available</div>
131
+ ) : (
132
+ // Render items normally using static children or other logic
133
+ <ListBoxItem>Static Item</ListBoxItem>
134
+ )
135
+ )}
136
+ </ListBox>
137
+ ```
138
+
139
+ This pattern provides access to the ListBox's state, focus status, and other render props following Bento's consistent render prop API.
140
+
141
+ ### Nested Collections with Sections
142
+ You can also render nested data inside a section using the exported `Collection` component:
143
+
144
+ ```tsx
145
+ /* v8 ignore next */
146
+ import React from 'react';
147
+ import { ListBox, ListBoxItem } from '@bento/listbox';
148
+ import style from './listbox.module.css';
149
+
150
+ /**
151
+ * Example component demonstrating ListBox with dynamic collections.
152
+ *
153
+ * @param {any} args - The component props including items array.
154
+ * @returns {JSX.Element} The rendered ListBox with dynamic items.
155
+ * @public
156
+ */
157
+ export function DynamicCollectionExample({ items, ...args }: any) {
158
+ return (
159
+ <ListBox {...args} className={style.listbox} items={items}>
160
+ {(item: any) => (
161
+ <ListBoxItem key={item.id} textValue={item.name}>
162
+ {item.name}
163
+ </ListBoxItem>
164
+ )}
165
+ </ListBox>
166
+ );
167
+ }
168
+ ```
169
+
170
+ ## Customization
171
+
172
+ The ListBox components provide extensive customization options through data attributes, slots, render props, and standard CSS styling. This section covers all available approaches to customize the appearance and behavior.
173
+
174
+ ### Styling with Data Attributes
175
+
176
+ All ListBox components expose their internal state through data attributes,
177
+ enabling CSS-based styling without JavaScript. This follows Bento's design
178
+ philosophy of returning styling control to CSS.
179
+
180
+ #### ListBox Container Attributes
181
+
182
+ The main `ListBox` component exposes these data attributes:
183
+
184
+ | Attribute | Description | Example Values |
185
+ | ---------------------------- | ------------------------------------------------- | ----------------------------- |
186
+ | `data-empty` | Applied when the listbox contains no items | "true" |
187
+ | `data-focused` | Applied when the listbox is focused | "true" |
188
+ | `data-focus-visible` | Applied when the listbox has keyboard focus | "true" |
189
+ | `data-layout` | The layout type | "stack" |
190
+ | `data-orientation` | The primary orientation | "vertical" / "horizontal" |
191
+ | `data-selection-mode` | The selection mode | "none" / "single" / "multiple"|
192
+ | `data-selection-behavior` | How selection behaves | "toggle" / "replace" |
193
+ | `data-allows-tab-navigation` | Whether tab navigation is enabled | "true" |
194
+ | `data-focus-wrap` | Whether focus wraps around the collection | "true" |
195
+
196
+ #### ListBoxItem Attributes
197
+
198
+ Individual `ListBoxItem` components expose these data attributes:
199
+
200
+ | Attribute | Description | Example Values |
201
+ | ------------------------ | ------------------------------------------ | ----------------------------- |
202
+ | `data-selected` | Applied when the item is selected | "true" |
203
+ | `data-disabled` | Applied when the item is disabled | "true" |
204
+ | `data-hovered` | Applied when the item is being hovered | "true" |
205
+ | `data-focused` | Applied when the item is focused | "true" |
206
+ | `data-focus-visible` | Applied when the item has keyboard focus | "true" |
207
+ | `data-pressed` | Applied when the item is being pressed | "true" |
208
+ | `data-level` | The nesting level (useful for indentation) | "0" / "1" / "2" |
209
+ | `data-selection-mode` | Inherited selection mode | "none" / "single" / "multiple"|
210
+ | `data-selection-behavior`| Inherited selection behavior | "toggle" / "replace" |
211
+ | `data-text-value` | The computed text value for the item | "Item text" |
212
+
213
+ #### ListBoxSection Attributes
214
+
215
+ The `ListBoxSection` component exposes:
216
+
217
+ | Attribute | Description | Example Values |
218
+ | ------------ | -------------------------------- | --------------- |
219
+ | `data-level` | The nesting level of the section | "0" / "1" / "2" |
220
+
221
+ #### CSS Styling Examples
222
+
223
+ ```css
224
+ /* Basic item styling */
225
+ [role="option"] {
226
+ padding: 8px 12px;
227
+ border-radius: 6px;
228
+ transition: all 0.15s ease-in-out;
229
+ cursor: pointer;
230
+ }
231
+
232
+ /* Selected items */
233
+ [role="option"][data-selected] {
234
+ background: Highlight;
235
+ color: HighlightText;
236
+ }
237
+
238
+ /* Hovered items */
239
+ [role="option"][data-hovered] {
240
+ background: color-mix(in srgb, Highlight 10%, transparent);
241
+ }
242
+
243
+ /* Disabled items */
244
+ [role="option"][data-disabled] {
245
+ opacity: 0.6;
246
+ cursor: not-allowed;
247
+ }
248
+
249
+ /* Focused items (keyboard navigation) */
250
+ [role="option"][data-focus-visible] {
251
+ outline: 2px solid Highlight;
252
+ outline-offset: -2px;
253
+ }
254
+
255
+ /* Combined states */
256
+ [role="option"][data-selected][data-hovered] {
257
+ background: color-mix(in srgb, Highlight 90%, white);
258
+ }
259
+
260
+ /* Empty state styling */
261
+ .listbox[data-empty] {
262
+ min-height: 100px;
263
+ display: flex;
264
+ align-items: center;
265
+ justify-content: center;
266
+ color: #64748b;
267
+ }
268
+
269
+ /* Section headers */
270
+ .section-header {
271
+ font-weight: 600;
272
+ font-size: 0.875rem;
273
+ color: #64748b;
274
+ padding: 6px 12px;
275
+ margin-bottom: 4px;
276
+ }
277
+ ```
278
+
279
+ ### Slots System
280
+
281
+ The components use Bento's `@bento/slots` package for fine-grained component overrides. Slots allow you to replace or wrap specific parts of the component tree with custom implementations.
282
+
283
+ #### Basic Slot Usage
284
+
285
+ ```tsx
286
+ /* v8 ignore next */
287
+ import React from 'react';
288
+ import { ListBox, ListBoxItem, ListBoxSection, Header, Collection } from '@bento/listbox';
289
+ import { useProps } from '@bento/use-props';
290
+ import style from './listbox.module.css';
291
+
292
+ //
293
+ // Slot namespace layout:
294
+ //
295
+ // ```
296
+ // bento-list (ListBox)
297
+ // ├── main-dishes (ListBoxSection)
298
+ // │ ├── header (Header)
299
+ // │ ├── chicken-teriyaki (ListBoxItem)
300
+ // │ └── salmon-bento (ListBoxItem)
301
+ // └── side-dishes (ListBoxSection)
302
+ // ├── header (Header)
303
+ // ├── pickled-vegetables (ListBoxItem)
304
+ // └── edamame (ListBoxItem)
305
+ // ```
306
+ //
307
+ // This example demonstrates several slot override patterns:
308
+ // 1. `side-dishes.header` – Custom header component with enhanced styling
309
+ // 2. `side-dishes.pickled-vegetables` – Override specific item in specific section
310
+ // 3. `main-dishes` – Override entire section styling
311
+ //
312
+
313
+ /**
314
+ * Example component demonstrating ListBox with dynamic sections and slot overrides.
315
+ *
316
+ * @param {any} args - The component props including categories and slots.
317
+ * @returns {JSX.Element} The rendered ListBox with slotted dynamic sections.
318
+ * @public
319
+ */
320
+ export function SlotsDynamicSectionsExample({ categories, ...args }: any) {
321
+ const {
322
+ items: argItems,
323
+ slots: argSlots = {},
324
+ ...rest
325
+ } = args as {
326
+ items?: Iterable<unknown>;
327
+ slots?: Record<string, any>;
328
+ } & Record<string, unknown>;
329
+
330
+ const { apply } = useProps(rest);
331
+
332
+ //
333
+ // Default slot overrides for demo - these show different override patterns
334
+ //
335
+ const demoSlots: Record<string, any> = {
336
+ //
337
+ // Override a header in a specific section with custom styling
338
+ //
339
+ 'side-dishes.header': ({ props, original }: { props: Record<string, any>; original: React.ReactNode }) => (
340
+ <Header {...props}>🥢 {original}</Header>
341
+ ),
342
+
343
+ //
344
+ // Override another specific item with custom content
345
+ //
346
+ 'side-dishes.pickled-vegetables': ({ original }: { original: React.ReactNode }) => (
347
+ <div style={{ backgroundColor: '#4ade80', color: 'white', padding: '2px 6px', borderRadius: '4px' }}>
348
+ 🥒 {original} (Traditional)
349
+ </div>
350
+ ),
351
+
352
+ //
353
+ // Override an entire section with custom wrapper
354
+ //
355
+ 'main-dishes': ({ original }: { original: React.ReactNode }) => (
356
+ <div style={{ border: '2px dashed #f59e0b', padding: '8px', borderRadius: '6px' }}>{original}</div>
357
+ )
358
+ };
359
+
360
+ //
361
+ // Merge provided slots with demo slots (provided slots take precedence)
362
+ //
363
+ const mergedSlots = { ...demoSlots, ...argSlots };
364
+
365
+ return (
366
+ <ListBox
367
+ {...apply({ className: style.listbox })}
368
+ // Only set items if caller didn't already supply one
369
+ items={argItems ?? categories}
370
+ slot="bento-list"
371
+ slots={mergedSlots}
372
+ >
373
+ {(category: any) => (
374
+ <ListBoxSection key={category.id} slot={category.id}>
375
+ <Header slot="header">{category.name}</Header>
376
+ <Collection items={category.items}>
377
+ {(item: { id: string; name: string }) => (
378
+ <ListBoxItem key={item.id} textValue={item.name} slot={item.id}>
379
+ {item.name}
380
+ </ListBoxItem>
381
+ )}
382
+ </Collection>
383
+ </ListBoxSection>
384
+ )}
385
+ </ListBox>
386
+ );
387
+ }
388
+ ```
389
+
390
+ #### Advanced Slot Patterns
391
+
392
+ You can target specific items or sections using hierarchical slot names:
393
+
394
+ ```tsx
395
+ // Override a specific section header
396
+ const slots = {
397
+ 'my-listbox.fruits.header': ({ original, props }) => (
398
+ <Header {...props}>🍎 {original}</Header>
399
+ ),
400
+
401
+ // Override a specific item in a specific section
402
+ 'my-listbox.fruits.apple': ({ original }) => (
403
+ <div className="special-item">⭐ {original}</div>
404
+ ),
405
+
406
+ // Override an entire section
407
+ 'my-listbox.vegetables': ({ original }) => (
408
+ <div className="veggie-section">{original}</div>
409
+ )
410
+ };
411
+
412
+ <ListBox slot="my-listbox" slots={slots}>
413
+ <ListBoxSection slot="fruits">
414
+ <Header slot="header">Fruits</Header>
415
+ <ListBoxItem slot="apple">Apple</ListBoxItem>
416
+ <ListBoxItem slot="orange">Orange</ListBoxItem>
417
+ </ListBoxSection>
418
+ <ListBoxSection slot="vegetables">
419
+ <Header slot="header">Vegetables</Header>
420
+ <ListBoxItem slot="carrot">Carrot</ListBoxItem>
421
+ </ListBoxSection>
422
+ </ListBox>
423
+ ```
424
+
425
+ ### Render Props
426
+
427
+ The `ListBoxItem` component supports render prop patterns for dynamic content based on interaction state:
428
+
429
+ ```tsx
430
+ // ListBoxItem render prop with interaction state
431
+ <ListBoxItem>
432
+ {({ isSelected, isHovered, isDisabled }) => (
433
+ <div className={`item ${isSelected ? 'selected' : ''}`}>
434
+ {isHovered && '👆 '}
435
+ My Item
436
+ {isSelected && ' ✓'}
437
+ </div>
438
+ )}
439
+ </ListBoxItem>
440
+ ```
441
+
442
+ For ListBox-level render props, use the `renderEmptyState` prop to customize empty state display:
443
+
444
+ ```tsx
445
+ <ListBox
446
+ items={items}
447
+ renderEmptyState={({ isEmpty, isFocused, state, items }) => (
448
+ <div className="empty-state">
449
+ {isFocused ? 'No items found (focused)' : 'No items available'}
450
+ </div>
451
+ )}
452
+ >
453
+ {(item: any) => (
454
+ <ListBoxItem key={item.id} textValue={item.name}>
455
+ {item.name}
456
+ </ListBoxItem>
457
+ )}
458
+ </ListBox>
459
+ ```
460
+
461
+ ### Empty State Customization
462
+
463
+ Customize the appearance when no items are present:
464
+
465
+ ```tsx
466
+ <ListBox
467
+ renderEmptyState={({ isEmpty, isFocused }) => (
468
+ <div className="empty-state">
469
+ <span>📭</span>
470
+ <p>No items to display</p>
471
+ {isFocused && <p>Start typing to search...</p>}
472
+ </div>
473
+ )}
474
+ >
475
+ {/* Items when present */}
476
+ </ListBox>
477
+ ```
478
+
479
+ ### Accessibility Customization
480
+
481
+ All components support standard ARIA attributes for enhanced accessibility:
482
+
483
+ ```tsx
484
+ <ListBox
485
+ aria-label="Food menu"
486
+ aria-describedby="menu-description"
487
+ >
488
+ <ListBoxSection aria-label="Main courses">
489
+ <Header>Main Dishes</Header>
490
+ <ListBoxItem aria-label="Chicken teriyaki with rice">
491
+ Chicken Teriyaki
492
+ </ListBoxItem>
493
+ </ListBoxSection>
494
+ </ListBox>
495
+ ```
496
+
497
+ ### CSS-in-JS and Styled Components
498
+
499
+ The data attributes work seamlessly with CSS-in-JS libraries:
500
+
501
+ ```tsx
502
+ // Styled Components
503
+ const StyledListBox = styled.div`
504
+ &[data-focused] {
505
+ box-shadow: 0 0 0 2px blue;
506
+ }
507
+
508
+ [role="option"][data-selected] {
509
+ background: ${props => props.theme.primary};
510
+ }
511
+ `;
512
+
513
+ // Emotion
514
+ const listboxStyles = css`
515
+ &[data-empty] {
516
+ opacity: 0.5;
517
+ }
518
+ `;
519
+ ```
520
+
521
+ ### Animation and Transitions
522
+
523
+ Data attributes enable smooth state transitions:
524
+
525
+ ```css
526
+ [role="option"] {
527
+ transition: all 0.2s ease-in-out;
528
+ transform: translateY(0);
529
+ }
530
+
531
+ [role="option"][data-hovered] {
532
+ transform: translateY(-2px);
533
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
534
+ }
535
+
536
+ [role="option"][data-pressed] {
537
+ transform: translateY(0);
538
+ transition-duration: 0.1s;
539
+ }
540
+ ```
package/README.mdx CHANGED
@@ -57,7 +57,7 @@ When you provide an `items` prop, the `children` function receives **individual
57
57
 
58
58
  In this pattern, `children` is called for each item in the `items` array, receiving the individual item data to render `ListBoxItem` components.
59
59
 
60
- ### When no `items` prop is provided
60
+ ### When no `items` prop is provided
61
61
  When you don't provide an `items` prop but use `children` as a function, it follows **Bento's render prop pattern** and receives an object with render props:
62
62
 
63
63
  ```tsx
@@ -86,42 +86,50 @@ The ListBox components provide extensive customization options through data attr
86
86
 
87
87
  ### Styling with Data Attributes
88
88
 
89
- All ListBox components expose their internal state through `data-` attributes, enabling CSS-based styling without JavaScript. This follows Bento's design philosophy of returning styling control to CSS.
89
+ All ListBox components expose their internal state through data attributes,
90
+ enabling CSS-based styling without JavaScript. This follows Bento's design
91
+ philosophy of returning styling control to CSS.
90
92
 
91
93
  #### ListBox Container Attributes
92
94
 
93
95
  The main `ListBox` component exposes these data attributes:
94
96
 
95
- - `[data-empty]` - Applied when the listbox contains no items
96
- - `[data-focused]` - Applied when the listbox is focused
97
- - `[data-focus-visible]` - Applied when the listbox has keyboard focus
98
- - `[data-layout="stack"]` - The layout type (currently only "stack" supported)
99
- - `[data-orientation="vertical|horizontal"]` - The primary orientation
100
- - `[data-selection-mode="none|single|multiple"]` - The selection mode
101
- - `[data-selection-behavior="toggle|replace"]` - How selection behaves
102
- - `[data-allows-tab-navigation]` - Whether tab navigation is enabled
103
- - `[data-focus-wrap]` - Whether focus wraps around the collection
97
+ | Attribute | Description | Example Values |
98
+ | ---------------------------- | ------------------------------------------------- | ----------------------------- |
99
+ | `data-empty` | Applied when the listbox contains no items | "true" |
100
+ | `data-focused` | Applied when the listbox is focused | "true" |
101
+ | `data-focus-visible` | Applied when the listbox has keyboard focus | "true" |
102
+ | `data-layout` | The layout type | "stack" |
103
+ | `data-orientation` | The primary orientation | "vertical" / "horizontal" |
104
+ | `data-selection-mode` | The selection mode | "none" / "single" / "multiple"|
105
+ | `data-selection-behavior` | How selection behaves | "toggle" / "replace" |
106
+ | `data-allows-tab-navigation` | Whether tab navigation is enabled | "true" |
107
+ | `data-focus-wrap` | Whether focus wraps around the collection | "true" |
104
108
 
105
109
  #### ListBoxItem Attributes
106
110
 
107
111
  Individual `ListBoxItem` components expose these data attributes:
108
112
 
109
- - `[data-selected]` - Applied when the item is selected
110
- - `[data-disabled]` - Applied when the item is disabled
111
- - `[data-hovered]` - Applied when the item is being hovered
112
- - `[data-focused]` - Applied when the item is focused
113
- - `[data-focus-visible]` - Applied when the item has keyboard focus
114
- - `[data-pressed]` - Applied when the item is being pressed
115
- - `[data-level]` - The nesting level (useful for indentation)
116
- - `[data-selection-mode]` - Inherited selection mode
117
- - `[data-selection-behavior]` - Inherited selection behavior
118
- - `[data-text-value]` - The computed text value for the item
113
+ | Attribute | Description | Example Values |
114
+ | ------------------------ | ------------------------------------------ | ----------------------------- |
115
+ | `data-selected` | Applied when the item is selected | "true" |
116
+ | `data-disabled` | Applied when the item is disabled | "true" |
117
+ | `data-hovered` | Applied when the item is being hovered | "true" |
118
+ | `data-focused` | Applied when the item is focused | "true" |
119
+ | `data-focus-visible` | Applied when the item has keyboard focus | "true" |
120
+ | `data-pressed` | Applied when the item is being pressed | "true" |
121
+ | `data-level` | The nesting level (useful for indentation) | "0" / "1" / "2" |
122
+ | `data-selection-mode` | Inherited selection mode | "none" / "single" / "multiple"|
123
+ | `data-selection-behavior`| Inherited selection behavior | "toggle" / "replace" |
124
+ | `data-text-value` | The computed text value for the item | "Item text" |
119
125
 
120
126
  #### ListBoxSection Attributes
121
127
 
122
128
  The `ListBoxSection` component exposes:
123
129
 
124
- - `[data-level]` - The nesting level of the section
130
+ | Attribute | Description | Example Values |
131
+ | ------------ | -------------------------------- | --------------- |
132
+ | `data-level` | The nesting level of the section | "0" / "1" / "2" |
125
133
 
126
134
  #### CSS Styling Examples
127
135
 
@@ -199,12 +207,12 @@ const slots = {
199
207
  'my-listbox.fruits.header': ({ original, props }) => (
200
208
  <Header {...props}>🍎 {original}</Header>
201
209
  ),
202
-
210
+
203
211
  // Override a specific item in a specific section
204
212
  'my-listbox.fruits.apple': ({ original }) => (
205
213
  <div className="special-item">⭐ {original}</div>
206
214
  ),
207
-
215
+
208
216
  // Override an entire section
209
217
  'my-listbox.vegetables': ({ original }) => (
210
218
  <div className="veggie-section">{original}</div>
@@ -283,7 +291,7 @@ Customize the appearance when no items are present:
283
291
  All components support standard ARIA attributes for enhanced accessibility:
284
292
 
285
293
  ```tsx
286
- <ListBox
294
+ <ListBox
287
295
  aria-label="Food menu"
288
296
  aria-describedby="menu-description"
289
297
  >
@@ -306,7 +314,7 @@ const StyledListBox = styled.div`
306
314
  &[data-focused] {
307
315
  box-shadow: 0 0 0 2px blue;
308
316
  }
309
-
317
+
310
318
  [role="option"][data-selected] {
311
319
  background: ${props => props.theme.primary};
312
320
  }