@kb.ui/react 0.0.0-stage → 0.10.2
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 +767 -2
- package/dist/check-versions.js +34 -0
- package/dist/components/Badge/Badge.d.ts +15 -0
- package/dist/components/Button/Button.d.ts +19 -0
- package/dist/components/Callout/Callout.d.ts +19 -0
- package/dist/components/Card/Card.d.ts +12 -0
- package/dist/components/Checkbox/Checkbox.d.ts +23 -0
- package/dist/components/Code/Code.d.ts +3 -0
- package/dist/components/Combobox/Combobox.d.ts +65 -0
- package/dist/components/Container/Container.d.ts +14 -0
- package/dist/components/Dialog/Dialog.d.ts +50 -0
- package/dist/components/ErrorSummary/ErrorSummary.d.ts +28 -0
- package/dist/components/Fieldset/Fieldset.d.ts +17 -0
- package/dist/components/FileInput/FileInput.d.ts +59 -0
- package/dist/components/FormActions/FormActions.d.ts +10 -0
- package/dist/components/Grid/Grid.d.ts +12 -0
- package/dist/components/Heading/Heading.d.ts +293 -0
- package/dist/components/Inline/Inline.d.ts +14 -0
- package/dist/components/Input/Input.d.ts +25 -0
- package/dist/components/Link/Link.d.ts +6 -0
- package/dist/components/Menu/Menu.d.ts +34 -0
- package/dist/components/MultiSelect/MultiSelect.d.ts +67 -0
- package/dist/components/NumberField/NumberField.d.ts +53 -0
- package/dist/components/Panel/Panel.d.ts +75 -0
- package/dist/components/Progress/Progress.d.ts +17 -0
- package/dist/components/RadioGroup/RadioGroup.d.ts +45 -0
- package/dist/components/ScrollArea/ScrollArea.d.ts +17 -0
- package/dist/components/Select/Select.d.ts +39 -0
- package/dist/components/Separator/Separator.d.ts +9 -0
- package/dist/components/Split/Split.d.ts +20 -0
- package/dist/components/Stat/Stat.d.ts +15 -0
- package/dist/components/Status/Status.d.ts +22 -0
- package/dist/components/Switch/Switch.d.ts +41 -0
- package/dist/components/Text/Text.d.ts +15 -0
- package/dist/components/Textarea/Textarea.d.ts +24 -0
- package/dist/components/Toolbar/Toolbar.d.ts +31 -0
- package/dist/components/Tooltip/Tooltip.d.ts +20 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.js +1770 -0
- package/dist/index.js.map +1 -0
- package/dist/styles.css +1 -0
- package/dist/utils/kb.d.ts +11 -0
- package/dist/utils/layout.d.ts +10 -0
- package/package.json +53 -4
package/README.md
CHANGED
|
@@ -1,3 +1,768 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kb.ui/react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React components for forms, navigation, feedback, and layout. kbui uses [Base UI](https://base-ui.com) 1.9 for interaction and `@kb.ui/css` for styling, which this package includes as `@kb.ui/react/styles.css`. Import the stylesheet once, then use components throughout your app.
|
|
4
|
+
|
|
5
|
+
Default themes use monochrome light/dark surfaces, a persimmon accent, and shared tactile materials. This reference follows the source on `main`; check the [release notes](https://github.com/KhallilB/kbui/releases) for the exports available in an installed version.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import "@kb.ui/react/styles.css";
|
|
9
|
+
import { Button, Dialog, Input } from "@kb.ui/react";
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Requires `react` and `react-dom` 19 in the consuming project.
|
|
13
|
+
|
|
14
|
+
## Styling
|
|
15
|
+
|
|
16
|
+
Every component takes `className` and `style`. Components with inner parts, such as Input, Select and Checkbox, also take `classNames` keyed by part; the props type lists each part. kbui's CSS sits in the `kbui` cascade layer, so your classes win. See [Restyling kbui](../../docs/guides/restyling.md).
|
|
17
|
+
|
|
18
|
+
```tsx
|
|
19
|
+
<Input label="Email" className="w-full" classNames={{ control: "rounded-none" }} />
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Themes and customization
|
|
23
|
+
|
|
24
|
+
Components follow the current light or dark theme through shared semantic tokens. Use `Button` for actions and its `render` prop for links styled as actions. Custom classes and token overrides are supported; preserve readable color pairs, visible focus and clear disabled states in both themes.
|
|
25
|
+
|
|
26
|
+
See [Restyling kbui](../../docs/guides/restyling.md#theme-every-component-with-tokens) for paired color overrides and nested themes. Contributors should follow [Theme and state support](../../docs/guides/adding-a-component.md#theme-and-state-support).
|
|
27
|
+
|
|
28
|
+
## Button
|
|
29
|
+
|
|
30
|
+
Use a Button for an action such as saving a form or opening a dialog. Choose a variant to match the action’s importance.
|
|
31
|
+
|
|
32
|
+
| Prop | Type | Default | Notes |
|
|
33
|
+
|---|---|---|---|
|
|
34
|
+
| `children` | `ReactNode` | unset | Visible action label, or an icon paired with aria-label |
|
|
35
|
+
| `variant` | `"primary" \| "secondary" \| "ghost" \| "danger"` | `"primary"` | Main, supporting, quiet, or destructive action emphasis |
|
|
36
|
+
| `size` | `sm` / `md` / `lg` / `icon` | `md` | Height and padding; icon is square and requires aria-label |
|
|
37
|
+
| `type` | native button type | `button` | Set submit for form submission; use button for other form actions |
|
|
38
|
+
| `disabled` | `boolean` | `false` | Blocks interaction; explain unavailable actions in nearby text when needed |
|
|
39
|
+
| `render` | element | unset | Use an anchor with nativeButton=false and role=link for navigation |
|
|
40
|
+
| `className` | `string` | unset | Extra classes on the rendered control; function values are not supported |
|
|
41
|
+
|
|
42
|
+
All props accepted by a native button or Base UI's `Button` also work. To render a link, pass an anchor and tell Base UI it is not a native button:
|
|
43
|
+
|
|
44
|
+
```tsx
|
|
45
|
+
<Button render={<a href="/docs" />} nativeButton={false} role="link">Docs</Button>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Input
|
|
49
|
+
|
|
50
|
+
Use Input for text entry. It keeps the label, help text, and error message together, and has space for icons or actions at either end.
|
|
51
|
+
|
|
52
|
+
| Prop | Type | Default | Notes |
|
|
53
|
+
|---|---|---|---|
|
|
54
|
+
| `startContent` / `endContent` | `ReactNode` | | Icons or actions at either end; give actions accessible names |
|
|
55
|
+
| `label` | `string` | required | Visible label and accessible name |
|
|
56
|
+
| `visuallyHidden` | `boolean` | | Hides the label visually but keeps it for screen readers |
|
|
57
|
+
| `description` | `string` | | Help text below the field |
|
|
58
|
+
| `error` | `string` | | Shows an error message and marks the field invalid |
|
|
59
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Field height. Replaces the native `size` attribute |
|
|
60
|
+
| `className` | `string` | | Applied to the wrapper, not the input element |
|
|
61
|
+
|
|
62
|
+
Other native input props, including `value` and `defaultValue`, pass through to the input. Base UI's `onValueChange` is also supported.
|
|
63
|
+
|
|
64
|
+
### Search composition
|
|
65
|
+
|
|
66
|
+
Use `Input type="search"` with content slots and a `Button` when search needs a visible clear action. Your app handles filtering, submission, debounce, reset, and result announcements.
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { useRef, useState } from "react";
|
|
70
|
+
import { Button, Input } from "@kb.ui/react";
|
|
71
|
+
|
|
72
|
+
export function SearchExample() {
|
|
73
|
+
const [query, setQuery] = useState("");
|
|
74
|
+
const control = useRef<HTMLInputElement>(null);
|
|
75
|
+
return (
|
|
76
|
+
<Input
|
|
77
|
+
ref={control}
|
|
78
|
+
label="Search components"
|
|
79
|
+
type="search"
|
|
80
|
+
name="q"
|
|
81
|
+
value={query}
|
|
82
|
+
onValueChange={setQuery}
|
|
83
|
+
endContent={query ? (
|
|
84
|
+
<Button type="button" size="sm" variant="ghost" aria-label="Clear search"
|
|
85
|
+
onClick={() => { setQuery(""); control.current?.focus(); }}>
|
|
86
|
+
<span aria-hidden="true">×</span>
|
|
87
|
+
</Button>
|
|
88
|
+
) : undefined}
|
|
89
|
+
/>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The field label names the input. Give each action its own accessible name, and hide decorative icons with `aria-hidden`. Use `type="button"` on the clear action so it does not submit the form, then return focus to the input. Hide editing actions when the field is disabled or read-only. Adding or removing content at either end keeps the same input node, value, and focus. See the **Icons and actions** story for a working search example.
|
|
95
|
+
|
|
96
|
+
## Dialog
|
|
97
|
+
|
|
98
|
+
`Dialog` is composed from parts. Base UI handles focus trapping, closing on Escape and scroll locking.
|
|
99
|
+
|
|
100
|
+
| Part | Purpose |
|
|
101
|
+
|---|---|
|
|
102
|
+
| `Dialog` | Root. Accepts `open`, `defaultOpen` and `onOpenChange` for controlled use. |
|
|
103
|
+
| `Dialog.Trigger` | Opens the dialog. Use `render={<Button />}` to style it as a button. |
|
|
104
|
+
| `Dialog.Content` | The dialog. `title` and `description` set its accessible name and description; `container` changes where it mounts. |
|
|
105
|
+
| `Dialog.Title`, `Dialog.Description` | For custom layouts. Use these or the `Dialog.Content` props in a given dialog, not both, or it gets two titles. |
|
|
106
|
+
| `Dialog.Header`, `Dialog.Body`, `Dialog.Footer` | Optional structured sections; accept native `div` props and refs. Padding follows `--kb-dialog-{header,body,footer}-padding`. |
|
|
107
|
+
| `Dialog.Actions` | Aligns buttons along the bottom right. |
|
|
108
|
+
| `Dialog.Close` | Closes the dialog. |
|
|
109
|
+
|
|
110
|
+
| Prop on root or Content | Type | Default | Notes |
|
|
111
|
+
|---|---|---|---|
|
|
112
|
+
| `open` on Dialog | `boolean` | uncontrolled | Current visibility when your app controls the dialog |
|
|
113
|
+
| `defaultOpen` on Dialog | `boolean` | `false` | Initial visibility; avoid starting open in a reading surface |
|
|
114
|
+
| `onOpenChange` on Dialog | Base UI callback | unset | Receives the next visibility and change details |
|
|
115
|
+
| `title` on Content | `ReactNode` | unset | Visible title and accessible name; use Dialog.Title for custom markup instead |
|
|
116
|
+
| `description` on Content | `ReactNode` | unset | Supporting description; use Dialog.Description for custom markup instead |
|
|
117
|
+
| `container` on Content | portal container | document body | Themed host for a nested dialog |
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
<Dialog>
|
|
121
|
+
<Dialog.Trigger render={<Button />}>Open</Dialog.Trigger>
|
|
122
|
+
<Dialog.Content title="Rename file">
|
|
123
|
+
<Input label="Name" />
|
|
124
|
+
<Dialog.Actions>
|
|
125
|
+
<Dialog.Close render={<Button variant="ghost" />}>Cancel</Dialog.Close>
|
|
126
|
+
<Button>Save</Button>
|
|
127
|
+
</Dialog.Actions>
|
|
128
|
+
</Dialog.Content>
|
|
129
|
+
</Dialog>
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Panel
|
|
133
|
+
|
|
134
|
+
Use Panel for a section that needs a header, body, and actions. Its parts help keep those areas aligned. Give the section an accessible name with `aria-labelledby`, pointing to the heading in `Panel.Header`.
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
<Panel tone="active" rail="status" aria-labelledby="queue-title">
|
|
138
|
+
<Panel.Header>
|
|
139
|
+
<h2 id="queue-title">Queue</h2>
|
|
140
|
+
<Panel.Toolbar><Button size="sm">Retry</Button></Panel.Toolbar>
|
|
141
|
+
</Panel.Header>
|
|
142
|
+
<Panel.Body>
|
|
143
|
+
<Panel.Well>…</Panel.Well>
|
|
144
|
+
</Panel.Body>
|
|
145
|
+
<Panel.Footer>…</Panel.Footer>
|
|
146
|
+
</Panel>
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
| Prop | Values | Default | Notes |
|
|
150
|
+
|---|---|---|---|
|
|
151
|
+
| `tone` | `quiet` / `default` / `sunken` / `active` / `critical` | `default` | Changes the surface emphasis; pair state colors with explanatory text |
|
|
152
|
+
| `rail` | `none` / `accent` / `status` | `none` | Accent stays the accent color; status follows the current tone |
|
|
153
|
+
| `density` | `compact` / `standard` | `standard` | Changes padding without changing semantics |
|
|
154
|
+
| `collapsible` | `boolean` | `false` | Enables Panel.Toggle and collapsible body behavior |
|
|
155
|
+
| `open` | `boolean` | uncontrolled | Current body visibility when collapsible is enabled |
|
|
156
|
+
| `defaultOpen` | `boolean` | `false` | Initial visibility for an uncontrolled collapsible panel |
|
|
157
|
+
| `onOpenChange` | `(open: boolean) => void` | unset | Update open here when your app controls visibility |
|
|
158
|
+
|
|
159
|
+
`quiet` removes the panel background; `sunken` gives it a recessed surface. Use `Panel.Well` for logs or other output that should sit inside the panel. Customize the shape with `--kb-panel-radius`, the rim with `--kb-panel-rim-top`, `--kb-panel-border`, and `--kb-panel-rim-bottom`, and the depth with `--kb-panel-shadow` or `--kb-panel-shadow-active`.
|
|
160
|
+
|
|
161
|
+
For additional lighting, use `--kb-panel-sheen`, `--kb-panel-backdrop`, `--kb-panel-glow`, `--kb-panel-glow-active`, and `--kb-panel-glow-critical`. These effects stay off by default. Active and critical tones change the upper rim and glow colors. The rail follows the panel’s rounded corners.
|
|
162
|
+
|
|
163
|
+
### Resizable panels
|
|
164
|
+
|
|
165
|
+
Put `Panel.Handle` between two panels in a `Panel.Group` to let people resize them. The handle sizes the panel before it, as a percentage of the group; the panel after it takes the remaining space. Name each handle with `aria-label` or `aria-labelledby`. A column group needs a height.
|
|
166
|
+
|
|
167
|
+
```tsx
|
|
168
|
+
<Panel.Group direction="row">
|
|
169
|
+
<Panel aria-labelledby="code-title">…</Panel>
|
|
170
|
+
<Panel.Handle aria-label="Resize code" defaultSize={50} min={25} max={75} />
|
|
171
|
+
<Panel aria-labelledby="view-title">…</Panel>
|
|
172
|
+
</Panel.Group>
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
`size` (controlled) or `defaultSize` (default `50`) sets the size of the panel before the handle in percent. `min` and `max` limit it (defaults `10` and `90`), `step` sets the arrow-key change (default `5`), and `onSizeChange` receives the next size after a key press or drag.
|
|
176
|
+
|
|
177
|
+
The handle follows the window splitter pattern. Arrow keys along the group's direction resize the panel, `Home` and `End` jump to the limits, and `Enter` collapses the panel to `min` and restores the previous size. Pointer drags work in both directions. Arrow keys do not flip in right-to-left layouts. Style the handle with `--kb-panel-handle-size`, `--kb-panel-handle-hit`, `--kb-panel-handle-grip`, `--kb-panel-handle-line` and `--kb-panel-handle-line-active`.
|
|
178
|
+
|
|
179
|
+
## Status
|
|
180
|
+
|
|
181
|
+
Use Status for a state such as running, blocked, or complete. Always include text so the meaning is clear without relying on color or an icon.
|
|
182
|
+
|
|
183
|
+
```tsx
|
|
184
|
+
<Status tone="running" appearance="chip" icon={<PlayIcon />} live>Running</Status>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
| Prop | Values | Default | Notes |
|
|
188
|
+
|---|---|---|---|
|
|
189
|
+
| `children` | `ReactNode` | unset | State text such as Running or Blocked; keep it meaningful without color |
|
|
190
|
+
| `tone` | `neutral` / `info` / `running` / `success` / `warning` / `blocked` | `neutral` | Reinforces the written state |
|
|
191
|
+
| `appearance` | `plain` / `chip` | `plain` | Plain stays inline; chip adds separation with a tinted surface |
|
|
192
|
+
| `icon` | `ReactNode` | unset | Optional decorative icon; the text still names the state |
|
|
193
|
+
| `live` | `boolean` | `false` | Adds role=status for changing text; does not move focus |
|
|
194
|
+
| `compact` | `boolean` | `false` | Tighter spacing and smaller text for dense layouts |
|
|
195
|
+
|
|
196
|
+
## Display and layout helpers
|
|
197
|
+
|
|
198
|
+
Use [Badge](#badge) for metadata, [Status](#status) for changing states, [Stat](#stat) for a headline value, [Progress](#progress) for completion, and [Callout](#callout) for a message. [ScrollArea](#scrollarea) keeps long content in a named region.
|
|
199
|
+
|
|
200
|
+
## Badge
|
|
201
|
+
|
|
202
|
+
Add a short label to a person, record, or resource. Keep the text meaningful without its color. Use Status when the information changes over time.
|
|
203
|
+
|
|
204
|
+
| Prop | Type | Default | Notes |
|
|
205
|
+
|---|---|---|---|
|
|
206
|
+
| `children` | `ReactNode` | unset | Short metadata such as Reviewer, Draft, or a branch name |
|
|
207
|
+
| `tone` | `neutral` / `info` / `success` / `warning` / `danger` | `neutral` | Reinforces the text with ink and tint |
|
|
208
|
+
| `appearance` | `chip` / `plain` | `chip` | Chip adds a tinted surface; plain stays inline |
|
|
209
|
+
| `mono` | `boolean` | `false` | Small uppercase monospace for short identifiers |
|
|
210
|
+
| `preserveCase` | `boolean` | `false` | Preserve case and spacing for branch names, paths, and other literal values |
|
|
211
|
+
|
|
212
|
+
Native span props pass through. Badge adds no focus stop or live announcement.
|
|
213
|
+
|
|
214
|
+
## Stat
|
|
215
|
+
|
|
216
|
+
Show a value with the label that explains it. Include units and a time period in the label or value when they affect the meaning.
|
|
217
|
+
|
|
218
|
+
| Prop | Type | Default | Notes |
|
|
219
|
+
|---|---|---|---|
|
|
220
|
+
| `label` | `ReactNode` | required | What the value measures; read before the value |
|
|
221
|
+
| `value` | `ReactNode` | required | Number or short text; include units where needed |
|
|
222
|
+
| `size` | `md` / `display` | `md` | Use display for one headline number, md for groups |
|
|
223
|
+
| `classNames` | keyed classes | unset | Style the label and value separately |
|
|
224
|
+
|
|
225
|
+
## Progress
|
|
226
|
+
|
|
227
|
+
Show how much of a known task is complete. Use a task label rather than a percentage as the accessible name.
|
|
228
|
+
|
|
229
|
+
| Prop | Type | Default | Notes |
|
|
230
|
+
|---|---|---|---|
|
|
231
|
+
| `label` | `ReactNode` | required | Visible task name and accessible progressbar label |
|
|
232
|
+
| `value` | `number` | required | Completed amount, from zero to max |
|
|
233
|
+
| `max` | `number` | `100` | Total amount; set it for counts such as three of five steps |
|
|
234
|
+
| `valueText` | `string` | formatted percentage | Visible and announced value, such as 3 of 5 files |
|
|
235
|
+
| `classNames` | keyed classes | unset | Style head, label, value, track, or indicator |
|
|
236
|
+
|
|
237
|
+
The current value stays available to assistive technology. Your app owns task completion and any separate completion announcement.
|
|
238
|
+
|
|
239
|
+
## Callout
|
|
240
|
+
|
|
241
|
+
Keep a useful message close to the content it explains. Give people a concrete next step when they can resolve the issue.
|
|
242
|
+
|
|
243
|
+
| Prop | Type | Default | Notes |
|
|
244
|
+
|---|---|---|---|
|
|
245
|
+
| `children` | `ReactNode` | unset | Message body; explain what happened and what to do next |
|
|
246
|
+
| `title` | `ReactNode` | unset | Short summary above the message |
|
|
247
|
+
| `tone` | `neutral` / `info` / `success` / `warning` / `danger` | `neutral` | Reinforces the message without replacing its wording |
|
|
248
|
+
| `icon` | `ReactNode` | unset | Decorative icon; hidden from assistive technology |
|
|
249
|
+
| `actions` | `ReactNode` | unset | Named buttons or links that help resolve the message |
|
|
250
|
+
| `live` | `boolean` | `false` | Adds role=status for changing message text; does not move focus |
|
|
251
|
+
| `classNames` | keyed classes | unset | Style icon, content, title, body, or actions |
|
|
252
|
+
|
|
253
|
+
## ScrollArea
|
|
254
|
+
|
|
255
|
+
Keep logs, activity, or other long content inside a height cap. Let ordinary page content scroll with the page when a separate region is unnecessary.
|
|
256
|
+
|
|
257
|
+
| Prop | Type | Default | Notes |
|
|
258
|
+
|---|---|---|---|
|
|
259
|
+
| `label` | `string` | required | Accessible name of the focusable scrolling region |
|
|
260
|
+
| `children` | `ReactNode` | required | Content inside the viewport |
|
|
261
|
+
| `maxHeight` | CSS length string | unset | Height cap, such as 12rem; longer content scrolls |
|
|
262
|
+
| `classNames` | keyed classes | unset | Style viewport, scrollbar, or thumb |
|
|
263
|
+
|
|
264
|
+
Tab reaches the viewport so keyboard users can scroll it. Keep the focus indicator visible and give the region a specific name such as Build output.
|
|
265
|
+
|
|
266
|
+
## Overlays and actions
|
|
267
|
+
|
|
268
|
+
Use [Menu](#menu) for a short list of actions, [Tooltip](#tooltip) for optional hints, and [Toolbar](#toolbar) for related actions that belong in a row. Use Dialog for a focused task with fields or a confirmation.
|
|
269
|
+
|
|
270
|
+
## Tooltip
|
|
271
|
+
|
|
272
|
+
Add a brief, optional hint to an already named control. Put essential instructions in visible text or a field description instead.
|
|
273
|
+
|
|
274
|
+
| Prop | Type | Default | Notes |
|
|
275
|
+
|---|---|---|---|
|
|
276
|
+
| `children` | `ReactElement` | required | Focusable trigger that accepts Base UI props and a ref |
|
|
277
|
+
| `content` | `ReactNode` | required | Short, non-interactive hint shown on hover or focus |
|
|
278
|
+
| `side` | positioner side | `top` | Preferred side; placement can adjust near viewport edges |
|
|
279
|
+
| `delay` | `number` | `400` | Hover delay in milliseconds |
|
|
280
|
+
| `container` | portal container | document body | Use a themed host when the popup belongs to a nested theme |
|
|
281
|
+
| `className` | `string` | unset | Class on the popup |
|
|
282
|
+
|
|
283
|
+
Give icon-only triggers their own aria-label. The tooltip is a description, not a replacement for the control's name. Do not put links, buttons, or required instructions in the popup.
|
|
284
|
+
|
|
285
|
+
## Menu
|
|
286
|
+
|
|
287
|
+
Offer a short list of actions without leaving the current context. Use a Select when people are choosing a saved field value.
|
|
288
|
+
|
|
289
|
+
| Part | Props and responsibility |
|
|
290
|
+
|---|---|
|
|
291
|
+
| `Menu` | Root; use open/defaultOpen and onOpenChange when your app controls visibility |
|
|
292
|
+
| `Menu.Trigger` | Named trigger; render a Button for shared styling |
|
|
293
|
+
| `Menu.Content` | Popup; side defaults to bottom, align to start; container chooses the themed portal host |
|
|
294
|
+
| `Menu.Item` | Action text and click handler; disabled prevents selection |
|
|
295
|
+
| `Menu.Separator` | Divides related groups without adding a focus stop |
|
|
296
|
+
|
|
297
|
+
Name the trigger, keep action labels specific, and retain the default arrow-key and Escape behavior. A menu item should perform an action rather than contain another button.
|
|
298
|
+
|
|
299
|
+
## Toolbar
|
|
300
|
+
|
|
301
|
+
Group related actions, such as editing or filtering controls. Give the row an accessible name so people know what its controls affect.
|
|
302
|
+
|
|
303
|
+
| Part | Props and responsibility |
|
|
304
|
+
|---|---|
|
|
305
|
+
| `Toolbar` | Root; name with aria-label; Base UI orientation controls the keyboard direction |
|
|
306
|
+
| `Toolbar.Group` | Groups related controls inside the toolbar |
|
|
307
|
+
| `Toolbar.Button` | Action; variant accepts Button variants and defaults to ghost |
|
|
308
|
+
| `Toolbar.Separator` | Visual division between groups |
|
|
309
|
+
|
|
310
|
+
Tab enters the toolbar once; arrow keys move between its controls. Give icon-only actions their own accessible names. Use Checkbox or RadioGroup when a control represents a persistent choice rather than an action.
|
|
311
|
+
|
|
312
|
+
## `kb()`
|
|
313
|
+
|
|
314
|
+
`kb(name, attrs, className)` builds the class and `data-*` props for a component's root element. It omits values that are `false` or `undefined` and renders `true` as an empty attribute. It is mainly used when writing a new component; see [Adding a component](../../docs/guides/adding-a-component.md).
|
|
315
|
+
|
|
316
|
+
## Build and test
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
bun run --cwd packages/react test
|
|
320
|
+
bun run --cwd packages/react build
|
|
321
|
+
bun run --cwd packages/react typecheck
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Tests use Vitest and Testing Library in jsdom.
|
|
325
|
+
|
|
326
|
+
## Card and Grid
|
|
327
|
+
|
|
328
|
+
Combine [Card](#card) for related content and [Grid](#grid) for responsive arrangements.
|
|
329
|
+
|
|
330
|
+
## Card
|
|
331
|
+
|
|
332
|
+
Group related content with an optional title, summary, links, and actions. Card renders an article by default and adds no interaction of its own.
|
|
333
|
+
|
|
334
|
+
| Prop | Type | Default | Notes |
|
|
335
|
+
|---|---|---|---|
|
|
336
|
+
| `as` | `article` / `div` / `li` | `article` | Choose the container for the document structure; use li inside a list |
|
|
337
|
+
| `appearance` | `outlined` / `plain` | `outlined` | Outlined adds a raised surface; plain stays flat with a dividing line |
|
|
338
|
+
| `children` | `ReactNode` | unset | Related content; your app provides headings, links, and actions |
|
|
339
|
+
| `className`, `style`, `ref` | native element props | unset | Style and reference the chosen container |
|
|
340
|
+
|
|
341
|
+
Card adds no link, button, keyboard handler, or tab stop. If a link covers the whole card, keep other controls outside that link and style its focus state. Restyle with the card background, face, shadow, color, border, radius, and padding tokens; they share the theme's tactile materials.
|
|
342
|
+
|
|
343
|
+
## Grid
|
|
344
|
+
|
|
345
|
+
Arrange cards or other content in equal columns that fit the available width. Grid uses ordinary CSS layout, without an ARIA grid role or special keyboard navigation.
|
|
346
|
+
|
|
347
|
+
| Prop | Type | Default | Notes |
|
|
348
|
+
|---|---|---|---|
|
|
349
|
+
| `as` | `div` / `ul` / `ol` | `div` | Use ul or ol for a collection; children must then be list items |
|
|
350
|
+
| `layout` | `auto` / `stack` | `auto` | Auto fits equal columns to available width; stack uses one column |
|
|
351
|
+
| `children` | `ReactNode` | unset | Content in document and keyboard order |
|
|
352
|
+
| `className`, `style`, `ref` | native element props | unset | Style and reference the chosen container |
|
|
353
|
+
|
|
354
|
+
```tsx
|
|
355
|
+
<Grid as="ul" aria-label="Projects">
|
|
356
|
+
<Card as="li"><h2><a href="/project">Project</a></h2><p>Summary</p></Card>
|
|
357
|
+
</Grid>
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
Use --kb-grid-gap and --kb-grid-min-item-width to adjust spacing and column fit. Keep the visual order the same as the reading order.
|
|
361
|
+
|
|
362
|
+
## Checkbox
|
|
363
|
+
|
|
364
|
+
Use Checkbox when people can select options independently. It includes a label, help text, and error message. Pass `checked` and update it in `onCheckedChange`. Activating a mixed checkbox requests the checked state.
|
|
365
|
+
|
|
366
|
+
| Prop | Type | Default | Notes |
|
|
367
|
+
|---|---|---|---|
|
|
368
|
+
| `label` | `string` | required | Visible accessible label |
|
|
369
|
+
| `checked` | `boolean` | required | Controlled native checked state |
|
|
370
|
+
| `onCheckedChange` | `(checked: boolean) => void` | required | Next checked-state request |
|
|
371
|
+
| `indeterminate` | `boolean` | `false` | Announces mixed state; activation requests checked |
|
|
372
|
+
| `disabled` / `readOnly` | `boolean` | `false` | Block changes; disabled also leaves keyboard order |
|
|
373
|
+
| `description` / `error` | `string` | | Associated helper and invalid-state text |
|
|
374
|
+
| `visuallyHidden` | `boolean` | `false` | Hide label visually |
|
|
375
|
+
| `controlClassName` | `string` | | Added to the native checkbox |
|
|
376
|
+
| `ref` | `Ref<HTMLInputElement>` | | Native checkbox, including form and indeterminate state |
|
|
377
|
+
| `name` / `value` / `required` | native input props | | Form serialization and validation |
|
|
378
|
+
| `className` | `string` | | Root class |
|
|
379
|
+
|
|
380
|
+
```tsx
|
|
381
|
+
<Checkbox label="Receive release updates" name="updates" checked={updates} onCheckedChange={setUpdates} />
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Clicking the label or pressing Space calls `onCheckedChange`. The checkbox changes only when your app updates `checked`; otherwise its checked or mixed state stays as it was. Native input props are supported. `style` applies to the input, and CSS custom properties also reach the visible mark. Use `--kb-checkbox-size` to change its size. In forced colors, the native checkbox and its focus outline remain visible.
|
|
385
|
+
## RadioGroup
|
|
386
|
+
|
|
387
|
+
Use RadioGroup when people need to choose one option and see all the choices at once. Give the group a label and each item a unique string value. Arrow keys change the selection and skip disabled options.
|
|
388
|
+
|
|
389
|
+
| Prop | Type | Default | Notes |
|
|
390
|
+
|---|---|---|---|
|
|
391
|
+
| `label` | `string` | required | Visible accessible group label |
|
|
392
|
+
| `value` | `string \| null` | required | Controlled choice; null means no choice |
|
|
393
|
+
| `onValueChange` | `(value: string) => void` | required | Next choice request |
|
|
394
|
+
| `appearance` | `"standard" \| "segmented"` | `"standard"` | Segmented tray for compact single-choice controls |
|
|
395
|
+
| `selectionMotion` | `"slide" \| "none"` | `"slide"` | Segmented selection background glides or moves instantly |
|
|
396
|
+
| `selectionTone` | `"primary" \| "neutral"` | `"primary"` | Accent pill by default; neutral uses the raised surface |
|
|
397
|
+
| `disabled` | `boolean` | `false` | Disable every item |
|
|
398
|
+
| `name` | `string` | | Native form field name |
|
|
399
|
+
| `description` / `error` | `string` | | Associated help and invalid-state text |
|
|
400
|
+
| `visuallyHidden` | `boolean` | `false` | Hide group label visually |
|
|
401
|
+
| `ref` | `Ref<HTMLDivElement>` | | Group root |
|
|
402
|
+
|
|
403
|
+
```tsx
|
|
404
|
+
<RadioGroup label="Density" name="density" value={density} onValueChange={setDensity}>
|
|
405
|
+
<RadioGroup.Item value="compact">Compact</RadioGroup.Item>
|
|
406
|
+
<RadioGroup.Item value="comfortable">Comfortable</RadioGroup.Item>
|
|
407
|
+
</RadioGroup>
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
`RadioGroup.Item` forwards Base UI Radio props, including `value`, `disabled` and the native control ref. `className` styles the item label; `controlClassName` styles its radio slot. The group uses the shared theme colors and shadows. Adjust the control size with `--kb-radiogroup-size` and the spacing with `--kb-radiogroup-gap`.
|
|
411
|
+
|
|
412
|
+
Set `appearance="segmented"` for compact choices such as view, density, or a filter. The control still behaves as a radio group, rather than tabs with associated panels. Your app manages the value and resets it when the form resets. An item’s `required` prop participates in native form validation. Changing the appearance keeps the same controls and focus.
|
|
413
|
+
|
|
414
|
+
The segmented selection uses a pill shape with the primary accent color by default. Set `selectionTone="neutral"` for a raised surface with neutral text and borders. Both tones follow the current light or dark theme. The background slides along the padded track and follows option widths, wrapped rows and layout changes. Set `selectionMotion="none"` for instant changes. Reduced-motion preferences disable movement regardless of this setting; forced-colors mode uses the selected option’s system highlight.
|
|
415
|
+
|
|
416
|
+
In dark mode, the primary pill uses a darker orange with white text for contrast. Override `--kb-radiogroup-primary-background` and `--kb-radiogroup-primary-color` together to customize this pair without changing other primary controls.
|
|
417
|
+
|
|
418
|
+
## Select
|
|
419
|
+
|
|
420
|
+
Use Select to choose one option from a dropdown. Each option has a string value, a visible label, and an optional disabled flag. Pass `null` to show the placeholder. Your app stores the selected value and decides whether it is valid.
|
|
421
|
+
|
|
422
|
+
| Prop | Type | Default | Notes |
|
|
423
|
+
|---|---|---|---|
|
|
424
|
+
| `label` | `string` | required | Visible field label and accessible popup name |
|
|
425
|
+
| `value` | `string \| null` | required | Controlled selection; null means unset |
|
|
426
|
+
| `onValueChange` | `(value: string \| null) => void` | required | Next valid choice request |
|
|
427
|
+
| `options` | `readonly SelectOption[]` | required | Ordered unique values, labels and optional disabled flags |
|
|
428
|
+
| `placeholder` | `string` | `"Choose an option"` | Text for unset values |
|
|
429
|
+
| `description` / `error` | `string` | | Associated help and invalid-state text |
|
|
430
|
+
| `disabled` / `readOnly` | `boolean` | `false` | Prevent edits; disabled also blocks form submission |
|
|
431
|
+
| `name` | `string` | | Native hidden form field name |
|
|
432
|
+
| `container` | `Select.Portal.Props["container"]` | field root | Portal host; default retains nested theme |
|
|
433
|
+
| `controlClassName` / `popupClassName` | `string` | | Trigger and popup slot classes |
|
|
434
|
+
| `className` / `ref` | root div props | | Wrapper class and native root ref |
|
|
435
|
+
|
|
436
|
+
```tsx
|
|
437
|
+
<Select label="View" name="view" value={view} onValueChange={setView} options={[{ value: "recent", label: "Recent" }, { value: "all", label: "All records" }]} />
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Use the arrow keys or type to find an option, Enter to select it, and Escape to close the popup and return focus. Disabled options cannot be selected. When there are no options, the trigger is disabled and “No options available” appears below it. Opening the popup leaves the page scrollable. Pointer selection returns focus without a keyboard ring; keyboard dismissal keeps a visible focus indicator.
|
|
441
|
+
|
|
442
|
+
By default, the popup mounts inside the field root and inherits its theme. If you provide a custom `container`, apply the theme there too. Use `--kb-select-popup-min-width`, `--kb-select-max-height`, and `--kb-select-layer` to adjust the popup’s size and stacking order.
|
|
443
|
+
|
|
444
|
+
## Combobox
|
|
445
|
+
|
|
446
|
+
Use Combobox when people need to filter a longer option list by typing before choosing one value. Each option has a string `value`, a visible `label`, and an optional `disabled` flag. Pass `null` when nothing is selected.
|
|
447
|
+
|
|
448
|
+
| Prop | Type | Default | Notes |
|
|
449
|
+
|---|---|---|---|
|
|
450
|
+
| `label` | `string` | required | Visible field label and accessible combobox name |
|
|
451
|
+
| `options` | `readonly ComboboxOption[]` | required | Selectable options filtered by label |
|
|
452
|
+
| `value` | `string \| null` | required | Controlled selection; `null` means unset |
|
|
453
|
+
| `onValueChange` | `(value: string \| null) => void` | required | Called when an option is selected or cleared |
|
|
454
|
+
| `placeholder` | `string` | unset | Input placeholder shown when empty |
|
|
455
|
+
| `emptyMessage` | `ReactNode` | `"No matching options"` | Polite status text when no options match |
|
|
456
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Control height and text scale |
|
|
457
|
+
| `description` / `error` | `ReactNode` | unset | Associated help and invalid-state text |
|
|
458
|
+
| `disabled` / `readOnly` | `boolean` | `false` | Prevent edits; disabled also blocks form submission |
|
|
459
|
+
| `clearLabel` / `toggleLabel` | `string` | derived from `label` | Accessible names for the clear and toggle buttons |
|
|
460
|
+
| `container` | `Combobox.Portal.Props["container"]` | field root | Portal host; default retains nested theme |
|
|
461
|
+
| `classNames` | `ClassNames<ComboboxSlot>` | unset | Extra classes for inner parts |
|
|
462
|
+
|
|
463
|
+
```tsx
|
|
464
|
+
import { useState } from "react";
|
|
465
|
+
import { Combobox } from "@kb.ui/react";
|
|
466
|
+
|
|
467
|
+
const regions = [
|
|
468
|
+
{ value: "us-east-1", label: "US East (N. Virginia)" },
|
|
469
|
+
{ value: "eu-central-1", label: "EU Central (Frankfurt)" },
|
|
470
|
+
];
|
|
471
|
+
|
|
472
|
+
export function RegionCombobox() {
|
|
473
|
+
const [region, setRegion] = useState<string | null>("us-east-1");
|
|
474
|
+
return (
|
|
475
|
+
<Combobox
|
|
476
|
+
label="Deployment region"
|
|
477
|
+
options={regions}
|
|
478
|
+
value={region}
|
|
479
|
+
onValueChange={setRegion}
|
|
480
|
+
placeholder="Search regions..."
|
|
481
|
+
/>
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
## MultiSelect
|
|
487
|
+
|
|
488
|
+
Use MultiSelect when people need to search a longer list and keep multiple selections visible as removable chips. Selected values render inside a named chip toolbar with keyboard arrow/Backspace/Delete support and per-chip remove buttons.
|
|
489
|
+
|
|
490
|
+
| Prop | Type | Default | Notes |
|
|
491
|
+
|---|---|---|---|
|
|
492
|
+
| `label` | `string` | required | Visible field label and accessible combobox name |
|
|
493
|
+
| `options` | `readonly MultiSelectOption[]` | required | Selectable options filtered by label |
|
|
494
|
+
| `value` | `readonly string[]` | required | Controlled array of selected option values |
|
|
495
|
+
| `onValueChange` | `(value: string[]) => void` | required | Called when selections are added, removed, or cleared |
|
|
496
|
+
| `placeholder` | `string` | unset | Input placeholder |
|
|
497
|
+
| `emptyMessage` | `ReactNode` | `"No matching options"` | Polite status text when no options match |
|
|
498
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Control height and text scale |
|
|
499
|
+
| `description` / `error` | `ReactNode` | unset | Associated help and invalid-state text |
|
|
500
|
+
| `disabled` / `readOnly` | `boolean` | `false` | Prevent edits and chip removal |
|
|
501
|
+
| `removeLabel` | `(option: MultiSelectOption) => string` | `"Remove {option.label}"` | Accessible name for each chip remove button |
|
|
502
|
+
| `container` | `Combobox.Portal.Props["container"]` | field root | Portal host; default retains nested theme |
|
|
503
|
+
| `classNames` | `ClassNames<MultiSelectSlot>` | unset | Extra classes for inner parts |
|
|
504
|
+
|
|
505
|
+
```tsx
|
|
506
|
+
import { useState } from "react";
|
|
507
|
+
import { MultiSelect } from "@kb.ui/react";
|
|
508
|
+
|
|
509
|
+
const scopes = [
|
|
510
|
+
{ value: "payments:read", label: "Payments read" },
|
|
511
|
+
{ value: "webhooks:manage", label: "Webhooks" },
|
|
512
|
+
{ value: "reporting:export", label: "Reporting export" },
|
|
513
|
+
];
|
|
514
|
+
|
|
515
|
+
export function ScopeMultiSelect() {
|
|
516
|
+
const [selected, setSelected] = useState<string[]>(["payments:read"]);
|
|
517
|
+
return (
|
|
518
|
+
<MultiSelect
|
|
519
|
+
label="API scopes"
|
|
520
|
+
options={scopes}
|
|
521
|
+
value={selected}
|
|
522
|
+
onValueChange={setSelected}
|
|
523
|
+
placeholder="Filter scopes..."
|
|
524
|
+
/>
|
|
525
|
+
);
|
|
526
|
+
}
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
## Switch
|
|
530
|
+
|
|
531
|
+
Use Switch for a preference that takes effect as soon as it changes. Pass `checked` and update it in `onCheckedChange`; your app handles saving and form reset. Switch uses a labelled native checkbox with `role="switch"`. Use Checkbox when people are selecting items instead.
|
|
532
|
+
|
|
533
|
+
| Prop | Type | Default | Notes |
|
|
534
|
+
|---|---|---|---|
|
|
535
|
+
| `label` | `string` | required | Associated visible label and accessible name |
|
|
536
|
+
| `checked` | `boolean` | required | Current controlled state |
|
|
537
|
+
| `onCheckedChange` | `(checked: boolean) => void` | required | Requests next state; owner updates checked |
|
|
538
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Visual track size (`36×20px`, `44×24px`, `56×32px`); `Fieldset` defaults nested switches to `"sm"` while keeping a 44px touch target |
|
|
539
|
+
| `tone` | `"accent" \| "neutral" \| "info" \| "success" \| "warning" \| "danger"` | `"accent"` | Checked-state track tone when `onTone` is unset |
|
|
540
|
+
| `offTone` / `onTone` | `SwitchTone` | `"neutral"` / `tone` | Independent track tone for unchecked and checked sides |
|
|
541
|
+
| `offColor` / `onColor` | `string` | | Custom CSS color for the unchecked or checked track |
|
|
542
|
+
| `description` / `error` | `string` | | Associated helper/error text; error sets aria-invalid |
|
|
543
|
+
| `disabled` / `readOnly` | `boolean` | `false` | Disabled blocks focus/changes; read-only keeps focus and form value while blocking edits |
|
|
544
|
+
| `visuallyHidden` | `boolean` | `false` | Hide label visually, keep its accessible name |
|
|
545
|
+
| `offIcon` / `onIcon` | `ReactNode` | | Decorative slots; do not place interactive content inside |
|
|
546
|
+
| `name` / `value` / `form` / `required` | native input props | | Native form ownership, successful value and validation |
|
|
547
|
+
| `ref` | `Ref<HTMLInputElement>` | | Native checkbox, never an extra hidden control |
|
|
548
|
+
| `className` / `controlClassName` | `string` | | Root/native input class |
|
|
549
|
+
| `style` | `CSSProperties` | | Native input styles; CSS custom properties also reach visible track and thumb |
|
|
550
|
+
|
|
551
|
+
```tsx
|
|
552
|
+
import { useState } from "react";
|
|
553
|
+
import { Switch } from "@kb.ui/react";
|
|
554
|
+
|
|
555
|
+
export function Preference() {
|
|
556
|
+
const [checked, setChecked] = useState(false);
|
|
557
|
+
return <Switch label="Email updates" checked={checked} onCheckedChange={setChecked} name="updates" />;
|
|
558
|
+
}
|
|
559
|
+
```
|
|
560
|
+
|
|
561
|
+
Import `useState` from React and `Switch` from `@kb.ui/react`. Clicking or pressing Space calls `onCheckedChange`. Unchecked or disabled controls submit no value; a checked control submits its native value (`"on"` unless you supply one). Reset `checked` in the form’s `onReset` handler when needed. Use `offTone`/`onTone` or `offColor`/`onColor` when both sides of a toggle carry distinct state colors. The `switch` token group controls its appearance in both themes, and reduced motion removes the thumb’s travel animation.
|
|
562
|
+
|
|
563
|
+
## NumberField
|
|
564
|
+
|
|
565
|
+
Use NumberField for quantities people can type or adjust with step buttons. Your app sets the range and validates the value. See [Numeric fields](../../docs/guides/number-fields.md) for examples, keyboard behavior, and styling. Available since v0.6.0.
|
|
566
|
+
|
|
567
|
+
| Prop | Type | Default | Notes |
|
|
568
|
+
|---|---|---|---|
|
|
569
|
+
| `label` | `string` | required | Visible field name; include the quantity or unit |
|
|
570
|
+
| `value` | `number` or `null` | required | Controlled number; null means no answer |
|
|
571
|
+
| `onValueChange` | `(value: number \| null) => void` | required | Update your stored value after an edit |
|
|
572
|
+
| `min`, `max` | `number` | unbounded | Bounds for stepping; your app validates direct drafts |
|
|
573
|
+
| `step` | `number` | `1` | Positive increment and alignment |
|
|
574
|
+
| `locale` | `Intl.LocalesArgument` | runtime locale | Number formatting and editing locale |
|
|
575
|
+
| `size` | `sm` / `md` / `lg` | `md` | Control size; lg suits touch-heavy tasks |
|
|
576
|
+
| `description`, `error` | `string` | unset | Associated help or a specific correction; error marks the field invalid |
|
|
577
|
+
| `disabled`, `readOnly` | `boolean` | `false` | Prevent changes; disabled also prevents submission |
|
|
578
|
+
| `name`, `form`, `required` | native form props | unset / false | Form ownership and validation |
|
|
579
|
+
| `visuallyHidden` | `boolean` | `false` | Hide the visual label while keeping its accessible name |
|
|
580
|
+
| `decrementLabel`, `incrementLabel` | `string` | Decrease/Increase + label | Localized names for the step actions |
|
|
581
|
+
| `inputRef`, `inputProps` | input ref / native props | unset | Visible input access and supported native event or ARIA extensions |
|
|
582
|
+
| `className`, `groupClassName`, `inputClassName` | `string` | unset | Classes for root, step group, and input |
|
|
583
|
+
|
|
584
|
+
Native div props and the root ref pass through to the wrapper. Any `aria-describedby` values from the root and `inputProps` are added after the help and error IDs. Use the explicit NumberField props for the input’s value, type, disabled/read-only state, name, required state, and ref; `inputProps` cannot override those. Custom event handlers can prevent defaults, so take care to preserve keyboard behavior.
|
|
585
|
+
|
|
586
|
+
## FileInput
|
|
587
|
+
|
|
588
|
+
Use FileInput to choose files, review the selected list, and remove items. Your app decides which files to accept, keeps the File objects, and handles uploads. See [Retained file selection](../../docs/guides/file-inputs.md) for examples, keyboard behavior, and styling. Available since v0.6.0.
|
|
589
|
+
|
|
590
|
+
| Prop | Type | Default | Notes |
|
|
591
|
+
|---|---|---|---|
|
|
592
|
+
| `label` | `string` | required | Visible field name and accessible picker context |
|
|
593
|
+
| `items` | `readonly FileInputItem[]` | required | Retained files with stable ids, names, and optional descriptions |
|
|
594
|
+
| `onFiles` | `(files: File[]) => void` | required | Check the selection and update retained files in your app |
|
|
595
|
+
| `onRemove` | `(id: string) => void` | required | Request removal; update items to confirm it |
|
|
596
|
+
| `accept` | `string` | unset | Native picker hint, such as image/*; does not validate files |
|
|
597
|
+
| `multiple` | `boolean` | `true` | Allow multiple selection; use a singular chooseLabel for single mode |
|
|
598
|
+
| `disabled`, `readOnly` | `boolean` | `false` | Prevent edits while keeping the retained list visible |
|
|
599
|
+
| `description`, `error` | `string` | unset | Help or actionable rejection text associated with the field |
|
|
600
|
+
| `visuallyHidden` | `boolean` | `false` | Hide the visual label while preserving its accessible name |
|
|
601
|
+
| `chooseLabel` | `string` | Choose files | Localized visible picker action |
|
|
602
|
+
| `emptyMessage` | `string` | No files added. | Localized empty-state text |
|
|
603
|
+
| `removeLabel` | `(item: FileInputItem) => string` | Remove + filename | Accessible remove action; keep the filename in the name |
|
|
604
|
+
| `removedMessage` | `(item: FileInputItem) => string` | filename + removed. | Announcement after removal is confirmed |
|
|
605
|
+
| `selectionMessage` | `(count: number) => string` | count + files selected. | Announcement after native selection |
|
|
606
|
+
| `renderItem` | `(item: FileInputItem) => ReactNode` | name + description | Custom item content; keep visible file identity |
|
|
607
|
+
| `inputRef`, `triggerRef` | element refs | unset | Hidden native input and visible picker access |
|
|
608
|
+
| `triggerClassName`, `listClassName`, `itemClassName` | `string` | unset | Classes for picker, retained list, and items |
|
|
609
|
+
|
|
610
|
+
Root native div props/ref and className pass through. Root aria-describedby merges after helper/error. Item button refs remain internal to preserve focus; use public item/content classes and renderItem for presentation. Use these props and classes rather than reaching into individual item buttons. The `×` mark is decorative; removal has a full accessible filename label.
|
|
611
|
+
|
|
612
|
+
## Heading
|
|
613
|
+
|
|
614
|
+
Native `h1`–`h6` headings with visual size independent of rank. Prepared locally after 0.7.0; unreleased.
|
|
615
|
+
|
|
616
|
+
| Prop | Type | Default | Notes |
|
|
617
|
+
|---|---|---|---|
|
|
618
|
+
| `level` | `1` \| `2` \| `3` \| `4` \| `5` \| `6` | `2` | Document rank; choose from page structure |
|
|
619
|
+
| `size` | `sm` \| `md` \| `lg` \| `xl` \| `display` | From level | Levels 1–6 map to xl, lg, md, sm, sm, sm; display is an explicit hero size |
|
|
620
|
+
| `className`, `ref` | Native heading props | unset | Classes merge; ref targets native heading |
|
|
621
|
+
|
|
622
|
+
Use one page title and nest section ranks without skipping levels. Adjust `size` for context without changing the outline. Headings have no margin; use Grid or parent layout for spacing. See [Typography](../../docs/guides/typography.md) for composition, CSS recipes and accessibility guidance.
|
|
623
|
+
|
|
624
|
+
## Text
|
|
625
|
+
|
|
626
|
+
Body paragraphs, inline text and block grouping. Prepared locally after 0.7.0; unreleased.
|
|
627
|
+
|
|
628
|
+
| Prop | Type | Default | Notes |
|
|
629
|
+
|---|---|---|---|
|
|
630
|
+
| `as` | `p` \| `span` \| `div` | `p` | Use span inside paragraphs; div for block children |
|
|
631
|
+
| `size` | `sm` \| `md` \| `lg` | `md` | Existing small/body roles (13px, 15px), then 1.125rem |
|
|
632
|
+
| `tone` | `default` \| `muted` | `default` | Primary ink or readable secondary ink |
|
|
633
|
+
| `className`, `ref` | Native element props | unset | Ref type follows chosen element |
|
|
634
|
+
|
|
635
|
+
Body line height is 1.6; block content is bounded to 65ch by `--kb-text-measure`. Text has no margin. Inline spans keep natural flow. Use native `strong` and `em` for meaningful emphasis. Do not nest paragraphs or place block children inside the default paragraph.
|
|
636
|
+
|
|
637
|
+
## Link
|
|
638
|
+
|
|
639
|
+
Native anchor for navigation, with persistent underline and visible keyboard focus. Prepared locally after 0.7.0; unreleased.
|
|
640
|
+
|
|
641
|
+
| Prop | Type | Default | Notes |
|
|
642
|
+
|---|---|---|---|
|
|
643
|
+
| `href` | `string` | required | Navigation destination |
|
|
644
|
+
| `target`, `rel`, `download`, `aria-current` | Native anchor props | unset | Passed through without rewriting |
|
|
645
|
+
| `className`, `ref` | Native anchor props | unset | Ref targets anchor |
|
|
646
|
+
|
|
647
|
+
Use descriptive link text. Use Button for an action. Links inherit surrounding type size; Tab focuses, Enter follows, and Space retains native behavior. Callers own new-tab wording and target/rel policy. No disabled link or router adapter is provided; apply `kb-link` to a router component that renders an anchor with href. Color, underline and focus must remain visible.
|
|
648
|
+
|
|
649
|
+
## Code
|
|
650
|
+
|
|
651
|
+
Literal inline code, commands and paths in native `code`. Prepared locally after 0.7.0; unreleased.
|
|
652
|
+
|
|
653
|
+
| Prop | Type | Default | Notes |
|
|
654
|
+
|---|---|---|---|
|
|
655
|
+
| `children` | `ReactNode` | unset | Pass markup as a string to display it literally |
|
|
656
|
+
| `className`, `ref` | Native code props | unset | Ref targets code element |
|
|
657
|
+
|
|
658
|
+
Monospace text inherits surrounding ink and line height, uses a relative size and wraps long tokens. Case and whitespace remain intact; no HTML parsing occurs. This component styles inline fragments; multiline listings need a separate `pre`/`code` recipe without inline padding. Syntax highlighting and copy controls are outside this component.
|
|
659
|
+
|
|
660
|
+
## Container
|
|
661
|
+
|
|
662
|
+
Centered page boundary with responsive inline gutters. Native props and matching ref pass through. See [Layout composition](../../docs/guides/layout.md) for rules, CSS recipes and token overrides. Prepared locally after 0.8.0; unreleased.
|
|
663
|
+
|
|
664
|
+
| Prop | Values | Default |
|
|
665
|
+
|---|---|---|
|
|
666
|
+
| `as` | `div` `main` `section` `article` `aside` `header` `footer` | `div` |
|
|
667
|
+
| `size` | `sm` (40rem) `md` (64rem) `lg` (80rem) `full` (unbounded) | `lg` |
|
|
668
|
+
| `gutter` | Shared 1–2rem inline padding; false removes it | `true` |
|
|
669
|
+
|
|
670
|
+
Non-default generic native elements require an explicit `as`; native props and refs follow that element. Explicit `gutter` owns its data attribute even when caller attributes conflict. Widths include gutters. Use one page boundary; nested containers should disable gutters when the parent owns padding.
|
|
671
|
+
|
|
672
|
+
## Inline
|
|
673
|
+
|
|
674
|
+
Wrapping row for independent content or controls. Adds no toolbar role or keyboard handling; controls retain native tab order. Native props and matching ref pass through.
|
|
675
|
+
|
|
676
|
+
| Prop | Values | Default |
|
|
677
|
+
|---|---|---|
|
|
678
|
+
| `as` | `div` `ul` `ol` `nav` | `div` |
|
|
679
|
+
| `gap` | `none` `sm` (0.5rem) `md` (1rem) `lg` (1.5rem) | `md` |
|
|
680
|
+
| `align` | `start` `center` `end` `baseline` `stretch` | `center` |
|
|
681
|
+
| `justify` | `start` `center` `end` `between` | `start` |
|
|
682
|
+
|
|
683
|
+
Non-default generic native elements require an explicit `as`. Lists retain markers and native list spacing. Use li children. Choose Toolbar when actions require its coordinated arrow-key model. See [Layout composition](../../docs/guides/layout.md).
|
|
684
|
+
|
|
685
|
+
## Split
|
|
686
|
+
|
|
687
|
+
Two children form equal or weighted columns through layout-owned `.kb-split-track` wrappers. Below the available-width threshold, columns stack in source order. Layout uses CSS alone, including inside nested panels. Native props and matching ref pass through.
|
|
688
|
+
|
|
689
|
+
| Prop | Values | Default |
|
|
690
|
+
|---|---|---|
|
|
691
|
+
| `as` | `div` `section` `article` | `div` |
|
|
692
|
+
| `ratio` | `equal` (1:1) `wide-start` (2:1) `wide-end` (1:2) | `equal` |
|
|
693
|
+
| `collapse` | `sm` (32rem) `md` (48rem) `lg` (64rem) | `md` |
|
|
694
|
+
| `gap` | `none` `sm` `md` `lg`, same scale as Inline | `md` |
|
|
695
|
+
| `align` | `start` `center` `end` `baseline` `stretch` | `stretch` |
|
|
696
|
+
| `classNames` | `{ track?: string }`, applied to each column track | unset |
|
|
697
|
+
|
|
698
|
+
Provide two children; empty conditional children add no track. Each track owns column sizing, so Text keeps its reading measure and nested token overrides stay local. Non-default generic native elements require an explicit `as`. Use Grid for variable child counts. See [Layout composition](../../docs/guides/layout.md).
|
|
699
|
+
|
|
700
|
+
## Separator
|
|
701
|
+
|
|
702
|
+
Native hr thematic break; decorative dividers are hidden from assistive technology. Native hr props and ref pass through; orientation and decorative own role, aria-hidden and aria-orientation.
|
|
703
|
+
|
|
704
|
+
| Prop | Values | Default |
|
|
705
|
+
|---|---|---|
|
|
706
|
+
| `orientation` | `horizontal` `vertical` | `horizontal` |
|
|
707
|
+
| `decorative` | Hide a visual-only divider from assistive technology | `false` |
|
|
708
|
+
|
|
709
|
+
Vertical rules stretch inside Inline and have a 1rem minimum height. No tab stop or resizing interaction is added. See [Layout composition](../../docs/guides/layout.md).
|
|
710
|
+
|
|
711
|
+
## Textarea
|
|
712
|
+
|
|
713
|
+
Use Textarea for multiline notes, summaries, or configuration payloads. It pairs a native textarea with a persistent label, optional help text, and validation feedback.
|
|
714
|
+
|
|
715
|
+
| Prop | Type | Default | Notes |
|
|
716
|
+
|---|---|---|---|
|
|
717
|
+
| `label` | `string` | required | Visible field label and accessible name |
|
|
718
|
+
| `visuallyHidden` | `boolean` | `false` | Hides the label visually while keeping its accessible name |
|
|
719
|
+
| `description` | `string` | unset | Supporting help text below the control |
|
|
720
|
+
| `error` | `string` | unset | Validation message; marks the control invalid |
|
|
721
|
+
| `rows` | `number` | `4` | Initial visible line count on the native textarea |
|
|
722
|
+
| `resize` | `"vertical" \| "none" \| "both"` | `"vertical"` | Controls user drag-resizing axis |
|
|
723
|
+
| `onValueChange` | `(value: string) => void` | unset | Called with the next string value on change |
|
|
724
|
+
| `classNames` | `ClassNames<"label" \| "control" \| "description" \| "error">` | unset | Classes for inner parts |
|
|
725
|
+
|
|
726
|
+
Other native textarea props (`value`, `defaultValue`, `onChange`, `placeholder`, `disabled`, `readOnly`, `required`, `name`, `form`, `ref`) pass through to the `<textarea>` element. Adjust minimum height and padding with `--kb-textarea-min-height`, `--kb-textarea-padding-block`, and `--kb-textarea-padding-inline`.
|
|
727
|
+
|
|
728
|
+
## Fieldset
|
|
729
|
+
|
|
730
|
+
Use Fieldset to group related controls into a named form section using native `fieldset` and `legend` semantics. Setting `disabled` disables descendant form controls natively.
|
|
731
|
+
|
|
732
|
+
| Prop | Type | Default | Notes |
|
|
733
|
+
|---|---|---|---|
|
|
734
|
+
| `legend` | `ReactNode` | required | Section heading rendered inside the native legend |
|
|
735
|
+
| `visuallyHidden` | `boolean` | `false` | Hides the legend visually while keeping the group name |
|
|
736
|
+
| `description` | `ReactNode` | unset | Section help text linked through aria-describedby |
|
|
737
|
+
| `error` | `ReactNode` | unset | Group-level error linked through aria-describedby |
|
|
738
|
+
| `disabled` | `boolean` | `false` | Disables all descendant controls in the fieldset |
|
|
739
|
+
| `classNames` | `ClassNames<"legend" \| "description" \| "fields" \| "error">` | unset | Classes for inner parts |
|
|
740
|
+
|
|
741
|
+
Other native fieldset props and `ref` pass through to the `<fieldset>` element. Use `--kb-fieldset-gap`, `--kb-fieldset-fields-gap`, and `--kb-fieldset-legend-size` to tune spacing and legend typography.
|
|
742
|
+
|
|
743
|
+
## FormActions
|
|
744
|
+
|
|
745
|
+
Use FormActions at the bottom of a form or section to align submit, reset, and secondary buttons with consistent wrapping and spacing. Buttons stay in natural Tab order without toolbar arrow-key navigation.
|
|
746
|
+
|
|
747
|
+
| Prop | Type | Default | Notes |
|
|
748
|
+
|---|---|---|---|
|
|
749
|
+
| `align` | `"end" \| "start" \| "between"` | `"end"` | Horizontal button alignment |
|
|
750
|
+
| `divider` | `boolean` | `false` | Adds a top border and spacing above the action row |
|
|
751
|
+
| `children` | `ReactNode` | unset | Form buttons in reading and Tab order |
|
|
752
|
+
|
|
753
|
+
Other native div props and `ref` pass through. Use `--kb-formactions-gap` and `--kb-formactions-padding-top` to adjust spacing.
|
|
754
|
+
|
|
755
|
+
## ErrorSummary
|
|
756
|
+
|
|
757
|
+
Place ErrorSummary at the top of a form when submission fails so people can see what went wrong and jump directly to each invalid field. When `items` is empty, nothing is rendered.
|
|
758
|
+
|
|
759
|
+
| Prop | Type | Default | Notes |
|
|
760
|
+
|---|---|---|---|
|
|
761
|
+
| `items` | `readonly ErrorSummaryItem[]` | required | Ordered `{ id?, href, label }` entries linking to invalid fields |
|
|
762
|
+
| `title` | `ReactNode` | `"There is a problem"` | Heading text naming the alert region |
|
|
763
|
+
| `description` | `ReactNode` | unset | Optional recovery guidance above the error list |
|
|
764
|
+
| `headingLevel` | `2 \| 3 \| 4` | `2` | Heading rank for the summary title |
|
|
765
|
+
| `onItemSelect` | `(href: string, event: MouseEvent<HTMLAnchorElement>) => void` | unset | Called when a recovery link is clicked |
|
|
766
|
+
| `classNames` | `ClassNames<"title" \| "description" \| "list" \| "item" \| "link">` | unset | Classes for inner parts |
|
|
767
|
+
|
|
768
|
+
ErrorSummary renders an alert region with `tabIndex={-1}` so your submit handler can focus it when validation fails. Clicking an `#id` link focuses the matching control or the first enabled control inside a referenced group. Pair ErrorSummary with inline `error` props on each invalid field.
|