aidos-ui 4.0.0 → 4.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +14 -1
- package/CLAUDE.md +72 -0
- package/dist/BaseButton.js.map +1 -1
- package/dist/BaseLink.js.map +1 -1
- package/dist/BaseListItem.d.ts +1 -1
- package/dist/Calendar.d.ts +2 -2
- package/dist/DarkMode.js.map +1 -1
- package/dist/DatePicker.js.map +1 -1
- package/dist/Dialog.d.ts +3 -3
- package/dist/Dialog.js.map +1 -1
- package/dist/Dropdown.js.map +1 -1
- package/dist/Icon.d.ts +3 -3
- package/dist/Icon.js +2 -21
- package/dist/Icon.js.map +1 -1
- package/dist/Interactable.js.map +1 -1
- package/dist/NextJSRouterState.js.map +1 -1
- package/dist/OnVisible.d.ts +1 -1
- package/dist/OnVisible.js.map +1 -1
- package/dist/Popover.d.ts +3 -3
- package/dist/Popover.js.map +1 -1
- package/dist/Providers.d.ts +2 -2
- package/dist/RangeInput.d.ts +1 -1
- package/dist/RootView.js.map +1 -1
- package/dist/Select.d.ts +0 -1
- package/dist/Storage.d.ts +2 -1
- package/dist/Storage.js.map +1 -1
- package/dist/Stream.js.map +1 -1
- package/dist/Text.js.map +1 -1
- package/dist/TextInput.d.ts +3 -2
- package/dist/TextInput.js +13 -4
- package/dist/TextInput.js.map +1 -1
- package/dist/TextPairing.js.map +1 -1
- package/dist/Tooltip.d.ts +2 -2
- package/dist/Tooltip.js.map +1 -1
- package/dist/aria.js.map +1 -1
- package/dist/hash.js.map +1 -1
- package/dist/jss.d.ts +6 -6
- package/dist/jss.js +2 -2
- package/dist/jss.js.map +1 -1
- package/dist/numberToBase.js.map +1 -1
- package/dist/stateMachineContextFactory.js.map +1 -1
- package/dist/useCookie.js.map +1 -1
- package/dist/useKeyboard.js.map +1 -1
- package/dist/useNavigation.js.map +1 -1
- package/dist/useRefEffect.js.map +1 -1
- package/next-env.d.ts +2 -1
- package/next.config.js +2 -1
- package/package.json +27 -20
- package/src/BaseListItem.tsx +1 -1
- package/src/Calendar.tsx +2 -2
- package/src/Dialog.tsx +3 -3
- package/src/Icon.tsx +4 -30
- package/src/Popover.tsx +3 -3
- package/src/Providers.tsx +1 -1
- package/src/RangeInput.tsx +1 -1
- package/src/Storage.tsx +1 -1
- package/src/TextInput.tsx +17 -5
- package/src/Tooltip.tsx +2 -2
- package/src/docs/mdx.tsx +40 -0
- package/src/docs/searchIndex.ts +1 -1
- package/src/jss.tsx +3 -3
- package/src/pages/Badge.mdx +136 -14
- package/src/pages/Button.mdx +121 -63
- package/src/pages/Calendar.mdx +196 -2
- package/src/pages/Card.mdx +123 -47
- package/src/pages/Checkbox.mdx +103 -28
- package/src/pages/Dialog.mdx +172 -7
- package/src/pages/FlexLayout.mdx +185 -51
- package/src/pages/Hashing.mdx +199 -8
- package/src/pages/Icon.mdx +150 -42
- package/src/pages/IconButton.mdx +127 -116
- package/src/pages/Link.mdx +118 -47
- package/src/pages/List.mdx +167 -283
- package/src/pages/ListHeader.mdx +157 -27
- package/src/pages/Popover.mdx +177 -55
- package/src/pages/ProgressBar.mdx +186 -6
- package/src/pages/ProgressCircle.mdx +196 -13
- package/src/pages/RangeInput.mdx +189 -61
- package/src/pages/Tabs.mdx +202 -346
- package/src/pages/Text.mdx +102 -81
- package/src/pages/TextInput.mdx +169 -44
- package/src/pages/TextPairing.mdx +164 -115
- package/src/pages/TimeInput.mdx +142 -37
- package/src/pages/Tooltip.mdx +99 -12
- package/src/pages/_app.tsx +13 -3
- package/src/pages/css-in-js.mdx +196 -83
- package/src/pages/navigation.mdx +122 -20
- package/src/pages/useCookie.mdx +168 -7
- package/src/pages/useKeyboard.mdx +242 -5
- package/src/pages/useNavigation.mdx +244 -16
- package/src/pages/usePromise.mdx +271 -6
- package/src/pages/useRefEffect.mdx +230 -28
- package/tsconfig.json +13 -4
package/src/pages/_app.tsx
CHANGED
|
@@ -33,14 +33,22 @@ import { Column } from "../Column";
|
|
|
33
33
|
import { Icon } from "../Icon";
|
|
34
34
|
import { BaseLinkComponentOverrideContext } from "../BaseLink";
|
|
35
35
|
import { DocsMDXProvider, labelToID } from "../docs/mdx";
|
|
36
|
-
import { Pipeline
|
|
36
|
+
import type { Pipeline } from "@xenova/transformers";
|
|
37
37
|
import { pages } from "../docs/pages";
|
|
38
38
|
|
|
39
39
|
import { Inter } from "next/font/google";
|
|
40
40
|
|
|
41
41
|
const inter = Inter({ subsets: ["latin"] });
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
let transformersPromise: Promise<typeof import("@xenova/transformers")> | null =
|
|
44
|
+
null;
|
|
45
|
+
const getTransformers = () => {
|
|
46
|
+
if (!transformersPromise) {
|
|
47
|
+
transformersPromise = import("@xenova/transformers");
|
|
48
|
+
}
|
|
49
|
+
return transformersPromise;
|
|
50
|
+
};
|
|
51
|
+
|
|
44
52
|
const searchIndex = import("../docs/searchIndex").then(
|
|
45
53
|
(module) => module.index
|
|
46
54
|
);
|
|
@@ -170,6 +178,8 @@ export default function App({ Component, pageProps }: AppProps) {
|
|
|
170
178
|
return;
|
|
171
179
|
}
|
|
172
180
|
|
|
181
|
+
const { dot } = await getTransformers();
|
|
182
|
+
|
|
173
183
|
const queryEmbeddings = await generateEmbeddings(query, {
|
|
174
184
|
normalize: true,
|
|
175
185
|
pooling: "mean",
|
|
@@ -446,7 +456,7 @@ export default function App({ Component, pageProps }: AppProps) {
|
|
|
446
456
|
let modelPromise: Promise<Pipeline> | null = null;
|
|
447
457
|
|
|
448
458
|
const loadModel: () => Promise<Pipeline> = async () => {
|
|
449
|
-
const { pipeline } = await
|
|
459
|
+
const { pipeline } = await getTransformers();
|
|
450
460
|
if (modelPromise == null) {
|
|
451
461
|
modelPromise = pipeline("feature-extraction", "Xenova/all-MiniLM-L6-v2");
|
|
452
462
|
}
|
package/src/pages/css-in-js.mdx
CHANGED
|
@@ -1,127 +1,240 @@
|
|
|
1
1
|
import { Button } from "../Button";
|
|
2
2
|
import { Row } from "../Row";
|
|
3
|
-
import {
|
|
3
|
+
import { Column } from "../Column";
|
|
4
|
+
import { BaseView } from "../BaseView";
|
|
5
|
+
import { Span } from "../Text";
|
|
6
|
+
import { cssVar, mobile, tablet } from "../jss";
|
|
4
7
|
|
|
5
8
|
# CSS in JS
|
|
6
9
|
|
|
7
|
-
Aidos UI
|
|
10
|
+
Aidos UI uses a custom CSS-in-JS system called `jss`. Every component accepts a `jss` prop for styling, and the library includes utilities for theming, responsive design, and type-safe CSS variables.
|
|
8
11
|
|
|
9
|
-
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## The jss prop
|
|
10
15
|
|
|
11
|
-
|
|
16
|
+
All components accept a `jss` prop that works like inline styles but with additional capabilities:
|
|
12
17
|
|
|
13
18
|
```js
|
|
14
|
-
<
|
|
19
|
+
<BaseView jss={{ backgroundColor: "red", padding: 12 }} />
|
|
15
20
|
```
|
|
16
21
|
|
|
17
|
-
Internally
|
|
22
|
+
Internally, each property becomes an atomic CSS class with a deterministic hash, enabling server-side rendering and hydration:
|
|
18
23
|
|
|
19
24
|
```html
|
|
20
25
|
<style>
|
|
21
|
-
.x1uc1pme {
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
.x1kbdebd {
|
|
26
|
-
padding: 12;
|
|
27
|
-
}
|
|
26
|
+
.x1uc1pme { background: red; }
|
|
27
|
+
.x1kbdebd { padding: 12px; }
|
|
28
28
|
</style>
|
|
29
29
|
<div class="x1uc1pme x1kbdebd" />
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
---
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## Arrays and conditionals
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
The `jss` prop accepts arrays and falsy values for conditional styling:
|
|
37
37
|
|
|
38
38
|
```js
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
39
|
+
<BaseView
|
|
40
|
+
jss={[
|
|
41
|
+
{ padding: 16 },
|
|
42
|
+
isActive && { backgroundColor: "blue" },
|
|
43
|
+
isDisabled && { opacity: 0.5 },
|
|
44
|
+
]}
|
|
45
|
+
/>
|
|
43
46
|
```
|
|
44
47
|
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## Automatic pixel conversion
|
|
51
|
+
|
|
52
|
+
Numeric values are automatically converted to pixels for dimensional properties:
|
|
53
|
+
|
|
45
54
|
```js
|
|
46
|
-
jss
|
|
47
|
-
|
|
48
|
-
background: blue;
|
|
49
|
-
}
|
|
55
|
+
<BaseView jss={{ padding: 16, fontSize: 14, opacity: 0.5 }} />
|
|
56
|
+
// Results in: padding: 16px; font-size: 14px; opacity: 0.5;
|
|
50
57
|
```
|
|
51
58
|
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Pseudo-selectors
|
|
62
|
+
|
|
63
|
+
Use string keys for pseudo-classes and pseudo-elements:
|
|
64
|
+
|
|
52
65
|
```js
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
66
|
+
// Hover state
|
|
67
|
+
jss({ ":hover": { backgroundColor: "blue" } })
|
|
68
|
+
|
|
69
|
+
// Focus state
|
|
70
|
+
jss({ ":focus": { outline: "2px solid blue" } })
|
|
71
|
+
|
|
72
|
+
// First child
|
|
73
|
+
jss({ ":first-child": { marginTop: 0 } })
|
|
57
74
|
```
|
|
58
75
|
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Descendant selectors
|
|
79
|
+
|
|
80
|
+
Target child elements with space-prefixed selectors:
|
|
81
|
+
|
|
59
82
|
```js
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
83
|
+
// All child divs
|
|
84
|
+
jss({ " div": { padding: 8 } })
|
|
85
|
+
|
|
86
|
+
// Direct children
|
|
87
|
+
jss({ " > span": { color: "red" } })
|
|
64
88
|
```
|
|
65
89
|
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Media queries
|
|
93
|
+
|
|
94
|
+
Use media query strings as keys:
|
|
95
|
+
|
|
96
|
+
```js
|
|
97
|
+
jss({
|
|
98
|
+
padding: 8,
|
|
99
|
+
"@media (min-width: 750px)": {
|
|
100
|
+
padding: 16,
|
|
101
|
+
},
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Responsive helpers
|
|
108
|
+
|
|
109
|
+
The library provides helper functions for common breakpoints:
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import { mobile, tablet, laptop, desktop } from "aidos-ui";
|
|
113
|
+
|
|
114
|
+
<BaseView
|
|
115
|
+
jss={[
|
|
116
|
+
{ padding: 8 },
|
|
117
|
+
tablet({ padding: 16 }),
|
|
118
|
+
desktop({ padding: 24 }),
|
|
119
|
+
]}
|
|
120
|
+
/>
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
| Helper | Breakpoint |
|
|
124
|
+
|--------|------------|
|
|
125
|
+
| `mobile()` | max-width: 479px |
|
|
126
|
+
| `tablet()` | min-width: 480px |
|
|
127
|
+
| `laptop()` | min-width: 1024px |
|
|
128
|
+
| `desktop()` | min-width: 1280px |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
66
132
|
## CSS variables
|
|
67
133
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
- `--primary-background`
|
|
72
|
-
- `--secondary-background`
|
|
73
|
-
- `--divider`
|
|
74
|
-
- `--strong-divider`
|
|
75
|
-
- `--pressed-background`
|
|
76
|
-
- `--hovered-background`
|
|
77
|
-
- `--selected-background`
|
|
78
|
-
- `--nav-bar`
|
|
79
|
-
- `--warning`
|
|
80
|
-
- `--highlight`
|
|
81
|
-
- `--outline`
|
|
82
|
-
- `--light-highlight`
|
|
83
|
-
- `--primary-text`
|
|
84
|
-
- `--secondary-text`
|
|
85
|
-
- `--subtle-text`
|
|
86
|
-
- `--highlight-text`
|
|
87
|
-
- `--negative-text`
|
|
88
|
-
- `--light-text`
|
|
89
|
-
- `--background-button-positive`
|
|
90
|
-
- `--background-button-secondary`
|
|
91
|
-
- `--background-button-negative`
|
|
92
|
-
- `--background-button-disabled`
|
|
93
|
-
- `--spacing-xs`
|
|
94
|
-
- `--spacing-s`
|
|
95
|
-
- `--spacing-m`
|
|
96
|
-
- `--spacing-l`
|
|
97
|
-
- `--spacing-xl`
|
|
98
|
-
- `--spacing-xxl`
|
|
99
|
-
- `--spacing-xxxl`
|
|
100
|
-
- `--border-radius-s`
|
|
101
|
-
- `--border-radius-m`
|
|
102
|
-
- `--border-radius-l`
|
|
103
|
-
- `--nav-bar-height`
|
|
104
|
-
|
|
105
|
-
For example:
|
|
106
|
-
|
|
107
|
-
<Row justify="center">
|
|
134
|
+
Use the `cssVar()` helper for type-safe access to theme variables:
|
|
135
|
+
|
|
136
|
+
<Row justify="center" padding="medium">
|
|
108
137
|
<Button
|
|
109
|
-
jss={{ border: `
|
|
110
|
-
label="Hello"
|
|
138
|
+
jss={{ border: `4px solid ${cssVar("--warning")}` }}
|
|
111
139
|
color="positive"
|
|
112
140
|
onClick={() => {}}
|
|
113
|
-
|
|
141
|
+
>
|
|
142
|
+
Styled button
|
|
143
|
+
</Button>
|
|
114
144
|
</Row>
|
|
115
145
|
|
|
116
146
|
```js
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
</Row>
|
|
147
|
+
import { cssVar } from "aidos-ui";
|
|
148
|
+
|
|
149
|
+
<BaseView jss={{
|
|
150
|
+
backgroundColor: cssVar("--primary-background"),
|
|
151
|
+
color: cssVar("--primary-text"),
|
|
152
|
+
padding: cssVar("--spacing-m"),
|
|
153
|
+
}} />
|
|
125
154
|
```
|
|
126
155
|
|
|
127
156
|
---
|
|
157
|
+
|
|
158
|
+
## Available CSS variables
|
|
159
|
+
|
|
160
|
+
### Colors
|
|
161
|
+
|
|
162
|
+
| Variable | Purpose |
|
|
163
|
+
|----------|---------|
|
|
164
|
+
| `--primary-background` | Main background |
|
|
165
|
+
| `--secondary-background` | Alternate background |
|
|
166
|
+
| `--overlay-background` | Modal/popover background |
|
|
167
|
+
| `--divider` | Border/divider color |
|
|
168
|
+
| `--highlight` | Accent/brand color |
|
|
169
|
+
| `--warning` | Warning indicator |
|
|
170
|
+
|
|
171
|
+
### Text colors
|
|
172
|
+
|
|
173
|
+
| Variable | Purpose |
|
|
174
|
+
|----------|---------|
|
|
175
|
+
| `--primary-text` | Main text |
|
|
176
|
+
| `--secondary-text` | Supporting text |
|
|
177
|
+
| `--subtle-text` | Muted/disabled text |
|
|
178
|
+
| `--highlight-text` | Accent text |
|
|
179
|
+
| `--negative-text` | Error/destructive text |
|
|
180
|
+
| `--light-text` | Text on dark backgrounds |
|
|
181
|
+
|
|
182
|
+
### Interactive states
|
|
183
|
+
|
|
184
|
+
| Variable | Purpose |
|
|
185
|
+
|----------|---------|
|
|
186
|
+
| `--hovered-background` | Hover state |
|
|
187
|
+
| `--pressed-background` | Active/pressed state |
|
|
188
|
+
| `--selected-background` | Selected item |
|
|
189
|
+
|
|
190
|
+
### Button backgrounds
|
|
191
|
+
|
|
192
|
+
| Variable | Purpose |
|
|
193
|
+
|----------|---------|
|
|
194
|
+
| `--background-button-positive` | Positive action buttons |
|
|
195
|
+
| `--background-button-secondary` | Secondary buttons |
|
|
196
|
+
| `--background-button-negative` | Destructive buttons |
|
|
197
|
+
| `--background-button-disabled` | Disabled buttons |
|
|
198
|
+
|
|
199
|
+
### Spacing
|
|
200
|
+
|
|
201
|
+
| Variable | Size |
|
|
202
|
+
|----------|------|
|
|
203
|
+
| `--spacing-xs` | 4px |
|
|
204
|
+
| `--spacing-s` | 8px |
|
|
205
|
+
| `--spacing-m` | 12px |
|
|
206
|
+
| `--spacing-l` | 16px |
|
|
207
|
+
| `--spacing-xl` | 24px |
|
|
208
|
+
| `--spacing-xxl` | 32px |
|
|
209
|
+
| `--spacing-xxxl` | 48px |
|
|
210
|
+
|
|
211
|
+
### Border radius
|
|
212
|
+
|
|
213
|
+
| Variable | Size |
|
|
214
|
+
|----------|------|
|
|
215
|
+
| `--border-radius-s` | 4px |
|
|
216
|
+
| `--border-radius-m` | 8px |
|
|
217
|
+
| `--border-radius-l` | 12px |
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Using toClassnames directly
|
|
222
|
+
|
|
223
|
+
For custom components, use `toClassnames()` to convert style objects to class names:
|
|
224
|
+
|
|
225
|
+
```js
|
|
226
|
+
import { toClassnames } from "aidos-ui";
|
|
227
|
+
|
|
228
|
+
function CustomComponent({ active }) {
|
|
229
|
+
return (
|
|
230
|
+
<div
|
|
231
|
+
className={toClassnames([
|
|
232
|
+
{ padding: 16, borderRadius: 8 },
|
|
233
|
+
active && { backgroundColor: "blue" },
|
|
234
|
+
])}
|
|
235
|
+
>
|
|
236
|
+
Content
|
|
237
|
+
</div>
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
```
|
package/src/pages/navigation.mdx
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
import { List } from "../List";
|
|
2
2
|
import { ListButtonItem } from "../ListButtonItem";
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
# List Navigation
|
|
5
5
|
|
|
6
|
-
Lists support keyboard navigation
|
|
6
|
+
Lists support built-in keyboard navigation using the `useNavigation` hook. This creates an accessible, keyboard-friendly experience following WAI-ARIA patterns.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Enabling navigation
|
|
11
|
+
|
|
12
|
+
Use the `navigation` prop to enable or disable keyboard navigation:
|
|
7
13
|
|
|
8
14
|
<List ariaLabel="example" navigation={true}>
|
|
9
15
|
<ListButtonItem color="secondary" headline="Headline 1" onClick={() => {}} />
|
|
@@ -16,8 +22,20 @@ Lists support keyboard navigation by default via the `useNavigation` hook. It ca
|
|
|
16
22
|
/>
|
|
17
23
|
</List>
|
|
18
24
|
|
|
25
|
+
```js
|
|
26
|
+
<List ariaLabel="example" navigation={true}>
|
|
27
|
+
<ListButtonItem headline="Headline 1" onClick={() => {}} />
|
|
28
|
+
<ListButtonItem headline="Headline 2" onClick={() => {}} />
|
|
29
|
+
<ListButtonItem headline="Headline 3" onClick={() => {}} />
|
|
30
|
+
</List>
|
|
31
|
+
```
|
|
32
|
+
|
|
19
33
|
---
|
|
20
34
|
|
|
35
|
+
## Without navigation
|
|
36
|
+
|
|
37
|
+
When `navigation` is `false`, each item is a separate tab stop:
|
|
38
|
+
|
|
21
39
|
<List ariaLabel="example" navigation={false}>
|
|
22
40
|
<ListButtonItem color="secondary" headline="Headline 1" onClick={() => {}} />
|
|
23
41
|
<ListButtonItem color="secondary" headline="Headline 2" onClick={() => {}} />
|
|
@@ -30,27 +48,111 @@ Lists support keyboard navigation by default via the `useNavigation` hook. It ca
|
|
|
30
48
|
</List>
|
|
31
49
|
|
|
32
50
|
```js
|
|
33
|
-
<List ariaLabel="example" navigation={
|
|
34
|
-
<ListButtonItem
|
|
35
|
-
<ListButtonItem
|
|
36
|
-
<ListButtonItem
|
|
37
|
-
withDivider={false}
|
|
38
|
-
color="secondary"
|
|
39
|
-
headline="Headline 3"
|
|
40
|
-
onClick={() => {}}
|
|
41
|
-
/>
|
|
51
|
+
<List ariaLabel="example" navigation={false}>
|
|
52
|
+
<ListButtonItem headline="Headline 1" onClick={() => {}} />
|
|
53
|
+
<ListButtonItem headline="Headline 2" onClick={() => {}} />
|
|
54
|
+
<ListButtonItem headline="Headline 3" onClick={() => {}} />
|
|
42
55
|
</List>
|
|
56
|
+
```
|
|
43
57
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Keyboard controls
|
|
61
|
+
|
|
62
|
+
When navigation is enabled:
|
|
63
|
+
|
|
64
|
+
| Key | Action |
|
|
65
|
+
|-----|--------|
|
|
66
|
+
| **Arrow Down** | Move to next item |
|
|
67
|
+
| **Arrow Up** | Move to previous item |
|
|
68
|
+
| **Arrow Right** | Move to next item |
|
|
69
|
+
| **Arrow Left** | Move to previous item |
|
|
70
|
+
| **Enter / Space** | Activate the focused item |
|
|
71
|
+
| **Tab** | Move focus out of the list |
|
|
72
|
+
|
|
73
|
+
Navigation wraps around - pressing down on the last item moves to the first.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## How it works
|
|
78
|
+
|
|
79
|
+
The navigation system uses `tabIndex` management:
|
|
80
|
+
|
|
81
|
+
1. **Single tab stop**: The entire list is one tab stop
|
|
82
|
+
2. **Active item**: Gets `tabIndex="0"` (focusable)
|
|
83
|
+
3. **Other items**: Get `tabIndex="-1"` (not in tab order)
|
|
84
|
+
4. **Arrow keys**: Move the active state between items
|
|
85
|
+
|
|
86
|
+
This follows the [WAI-ARIA grid layout pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/examples/layout-grids/).
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## Benefits
|
|
91
|
+
|
|
92
|
+
**With navigation enabled:**
|
|
93
|
+
- Faster keyboard navigation (single Tab to enter list)
|
|
94
|
+
- Arrow keys to move between items
|
|
95
|
+
- Better for long lists
|
|
96
|
+
- More efficient for power users
|
|
97
|
+
|
|
98
|
+
**With navigation disabled:**
|
|
99
|
+
- Standard Tab behavior between items
|
|
100
|
+
- Simpler mental model
|
|
101
|
+
- Better for short lists (2-3 items)
|
|
102
|
+
- Each item is independently focusable
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Accessibility considerations
|
|
107
|
+
|
|
108
|
+
Always provide an `ariaLabel` for the list:
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
<List ariaLabel="Search results" navigation={true}>
|
|
112
|
+
{/* items */}
|
|
113
|
+
</List>
|
|
114
|
+
|
|
115
|
+
<List ariaLabel="User menu options" navigation={true}>
|
|
116
|
+
{/* items */}
|
|
53
117
|
</List>
|
|
54
118
|
```
|
|
55
119
|
|
|
120
|
+
This helps screen reader users understand the list's purpose.
|
|
121
|
+
|
|
56
122
|
---
|
|
123
|
+
|
|
124
|
+
## When to use navigation
|
|
125
|
+
|
|
126
|
+
**Enable navigation for:**
|
|
127
|
+
- Long lists (5+ items)
|
|
128
|
+
- Menu-like interfaces
|
|
129
|
+
- Search results
|
|
130
|
+
- Option lists
|
|
131
|
+
- File browsers
|
|
132
|
+
|
|
133
|
+
**Disable navigation for:**
|
|
134
|
+
- Short action lists (2-3 items)
|
|
135
|
+
- Form field groups
|
|
136
|
+
- Simple button groups
|
|
137
|
+
- When each item needs independent focus
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Implementation
|
|
142
|
+
|
|
143
|
+
Lists use the `useNavigation` hook internally:
|
|
144
|
+
|
|
145
|
+
```js
|
|
146
|
+
// Simplified internal implementation
|
|
147
|
+
function List({ navigation = true, children, ariaLabel }) {
|
|
148
|
+
const rootRef = useNavigation({ enabled: navigation });
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<ul ref={rootRef} aria-label={ariaLabel}>
|
|
152
|
+
{children}
|
|
153
|
+
</ul>
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
See the [useNavigation documentation](/useNavigation) for more details on the underlying hook.
|