@kb.ui/react 0.10.4 → 0.12.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.
Files changed (109) hide show
  1. package/README.md +142 -707
  2. package/dist/components/Accordion/Accordion.d.ts +33 -0
  3. package/dist/components/Avatar/Avatar.d.ts +19 -0
  4. package/dist/components/Code/Code.d.ts +26 -3
  5. package/dist/components/Code/tokenize.d.ts +5 -0
  6. package/dist/components/CodeBlock/CodeBlock.d.ts +10 -0
  7. package/dist/components/Collection/Collection.d.ts +99 -0
  8. package/dist/components/Collection/useCollection.d.ts +66 -0
  9. package/dist/components/CollectionList/CollectionList.d.ts +12 -0
  10. package/dist/components/CollectionRow/CollectionRow.d.ts +17 -0
  11. package/dist/components/Combobox/Combobox.d.ts +14 -2
  12. package/dist/components/ConfirmAction/ConfirmAction.d.ts +42 -0
  13. package/dist/components/CopyableText/CopyableText.d.ts +38 -0
  14. package/dist/components/CopyableText/content.d.ts +14 -0
  15. package/dist/components/Dashboard/Dashboard.d.ts +17 -0
  16. package/dist/components/DescriptionList/DescriptionList.d.ts +20 -0
  17. package/dist/components/Dialog/Dialog.d.ts +3 -1
  18. package/dist/components/Disclosure/Disclosure.d.ts +21 -0
  19. package/dist/components/EmptyState/EmptyState.d.ts +30 -0
  20. package/dist/components/Form/Form.d.ts +19 -0
  21. package/dist/components/FormSection/FormSection.d.ts +26 -0
  22. package/dist/components/Gallery/Gallery.d.ts +26 -0
  23. package/dist/components/Grid/Grid.d.ts +17 -6
  24. package/dist/components/Image/Image.d.ts +20 -0
  25. package/dist/components/Link/Link.d.ts +15 -2
  26. package/dist/components/PageHeader/PageHeader.d.ts +27 -0
  27. package/dist/components/Panel/Panel.d.ts +3 -1
  28. package/dist/components/Popover/Popover.d.ts +55 -0
  29. package/dist/components/Settings/Settings.d.ts +11 -0
  30. package/dist/components/Skeleton/Skeleton.d.ts +34 -0
  31. package/dist/components/Spinner/Spinner.d.ts +26 -0
  32. package/dist/components/Stack/Stack.d.ts +15 -0
  33. package/dist/components/StatsRow/StatsRow.d.ts +33 -0
  34. package/dist/components/SupportingPane/SupportingPane.d.ts +15 -0
  35. package/dist/components/Table/Table.d.ts +65 -0
  36. package/dist/components/Tabs/Tabs.d.ts +69 -0
  37. package/dist/components/Tabs/index.d.ts +1 -0
  38. package/dist/components/Thumbnail/Thumbnail.d.ts +14 -0
  39. package/dist/components/Toast/Toast.d.ts +72 -0
  40. package/dist/index.d.ts +39 -4
  41. package/dist/index.js +3901 -1238
  42. package/dist/index.js.map +1 -1
  43. package/dist/styles.css +1 -1
  44. package/dist/utils/CollapsiblePanel.d.ts +10 -0
  45. package/dist/utils/useClipboard.d.ts +28 -0
  46. package/docs/components/Accordion.md +66 -0
  47. package/docs/components/Avatar.md +80 -0
  48. package/docs/components/Badge.md +37 -0
  49. package/docs/components/Button.md +46 -0
  50. package/docs/components/Callout.md +41 -0
  51. package/docs/components/Card.md +41 -0
  52. package/docs/components/Checkbox.md +60 -0
  53. package/docs/components/Code.md +77 -0
  54. package/docs/components/CodeBlock.md +77 -0
  55. package/docs/components/Collection.md +183 -0
  56. package/docs/components/CollectionList.md +44 -0
  57. package/docs/components/CollectionRow.md +62 -0
  58. package/docs/components/Combobox.md +88 -0
  59. package/docs/components/ConfirmAction.md +100 -0
  60. package/docs/components/Container.md +41 -0
  61. package/docs/components/CopyableText.md +93 -0
  62. package/docs/components/Dashboard.md +81 -0
  63. package/docs/components/DescriptionList.md +61 -0
  64. package/docs/components/Dialog.md +84 -0
  65. package/docs/components/Disclosure.md +53 -0
  66. package/docs/components/EmptyState.md +50 -0
  67. package/docs/components/ErrorSummary.md +48 -0
  68. package/docs/components/Fieldset.md +42 -0
  69. package/docs/components/FileInput.md +74 -0
  70. package/docs/components/Form.md +67 -0
  71. package/docs/components/FormActions.md +45 -0
  72. package/docs/components/FormSection.md +57 -0
  73. package/docs/components/Gallery.md +84 -0
  74. package/docs/components/Grid.md +66 -0
  75. package/docs/components/Heading.md +40 -0
  76. package/docs/components/Image.md +62 -0
  77. package/docs/components/Inline.md +42 -0
  78. package/docs/components/Input.md +82 -0
  79. package/docs/components/Link.md +52 -0
  80. package/docs/components/Menu.md +44 -0
  81. package/docs/components/MultiSelect.md +59 -0
  82. package/docs/components/NumberField.md +65 -0
  83. package/docs/components/PageHeader.md +68 -0
  84. package/docs/components/Panel.md +153 -0
  85. package/docs/components/Popover.md +89 -0
  86. package/docs/components/Progress.md +37 -0
  87. package/docs/components/RadioGroup.md +69 -0
  88. package/docs/components/ScrollArea.md +40 -0
  89. package/docs/components/Select.md +71 -0
  90. package/docs/components/Separator.md +40 -0
  91. package/docs/components/Settings.md +57 -0
  92. package/docs/components/Skeleton.md +86 -0
  93. package/docs/components/Spinner.md +45 -0
  94. package/docs/components/Split.md +47 -0
  95. package/docs/components/Stack.md +54 -0
  96. package/docs/components/Stat.md +34 -0
  97. package/docs/components/StatsRow.md +80 -0
  98. package/docs/components/Status.md +48 -0
  99. package/docs/components/SupportingPane.md +59 -0
  100. package/docs/components/Switch.md +73 -0
  101. package/docs/components/Table.md +105 -0
  102. package/docs/components/Tabs.md +89 -0
  103. package/docs/components/Text.md +36 -0
  104. package/docs/components/Textarea.md +47 -0
  105. package/docs/components/Thumbnail.md +66 -0
  106. package/docs/components/Toast.md +130 -0
  107. package/docs/components/Toolbar.md +39 -0
  108. package/docs/components/Tooltip.md +42 -0
  109. package/package.json +3 -2
@@ -0,0 +1,65 @@
1
+ # NumberField
2
+
3
+ Use `NumberField` for quantities people can type or adjust with step buttons. Your app sets the range and validates the value. See [Numeric fields](https://github.com/KhallilB/kbui/blob/main/docs/guides/number-fields.md) for examples, keyboard behavior, and styling. Available since v0.6.0.
4
+
5
+ [All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-numberfield--docs)
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import "@kb.ui/react/styles.css";
11
+ import { NumberField } from "@kb.ui/react";
12
+ import { useState } from "react";
13
+
14
+ export function Example() {
15
+ const [value, setValue] = useState<number | null>(1);
16
+ const error =
17
+ value === null || !Number.isInteger(value) || value < 0 || value > 99
18
+ ? "Enter a whole number from 0 to 99."
19
+ : "";
20
+ return (
21
+ <NumberField
22
+ label="Quantity"
23
+ value={value}
24
+ onValueChange={setValue}
25
+ min={0}
26
+ max={99}
27
+ step={1}
28
+ error={error}
29
+ />
30
+ );
31
+ }
32
+ ```
33
+
34
+ The field can be empty (`null`), and directly typed values remain available for your app to validate. The example validates a whole-number quantity; `min`, `max`, and `step` control the step buttons and stepping keys. See [numeric-field state and interaction](https://github.com/KhallilB/kbui/blob/main/docs/guides/number-fields.md#state-and-interaction) for locale and draft behavior.
35
+
36
+ ## More examples
37
+
38
+ - [An unanswered quantity](https://kbui.kcb.pro/storybook/?path=/story/components-numberfield--empty): Use `null` for an empty field.
39
+ - [Validation feedback](https://kbui.kcb.pro/storybook/?path=/story/components-numberfield--invalid): Explain a value that needs correction.
40
+ - [Fractional steps](https://kbui.kcb.pro/storybook/?path=/story/components-numberfield--fractional): Compare non-integer increments.
41
+
42
+ ## Reference
43
+
44
+ | Prop | Type | Default | Notes |
45
+ | ----------------------------------------------- | --------------------------------- | ------------------------- | ----------------------------------------------------------------------- |
46
+ | `label` | `string` | required | Visible field name; include the quantity or unit |
47
+ | `value` | `number` or `null` | required | Controlled number; null means no answer |
48
+ | `onValueChange` | `(value: number \| null) => void` | required | Update your stored value after an edit |
49
+ | `min`, `max` | `number` | unbounded | Bounds for stepping; your app validates direct drafts |
50
+ | `step` | `number` | `1` | Positive increment and alignment |
51
+ | `locale` | `Intl.LocalesArgument` | runtime locale | Number formatting and editing locale |
52
+ | `size` | `sm` / `md` / `lg` | `md` | Control size; lg suits touch-heavy tasks |
53
+ | `description`, `error` | `string` | unset | Associated help or a specific correction; error marks the field invalid |
54
+ | `disabled`, `readOnly` | `boolean` | `false` | Prevent changes; disabled also prevents submission |
55
+ | `name`, `form`, `required` | native form props | unset / false | Form ownership and validation |
56
+ | `visuallyHidden` | `boolean` | `false` | Hide the visual label while keeping its accessible name |
57
+ | `decrementLabel`, `incrementLabel` | `string` | Decrease/Increase + label | Localized names for the step actions |
58
+ | `inputRef`, `inputProps` | input ref / native props | unset | Visible input access and supported native event or ARIA extensions |
59
+ | `className`, `groupClassName`, `inputClassName` | `string` | unset | Classes for root, step group, and input |
60
+
61
+ Native `<div>` props and the root `ref` apply to the wrapper. Root and `inputProps` descriptions follow the help and error IDs in `aria-describedby`. Set the input’s value, type, disabled/read-only state, name, required state and ref through `NumberField` props; `inputProps` cannot override them. Custom event handlers can prevent default actions, so check keyboard behavior after adding them.
62
+
63
+ ## Related components
64
+
65
+ Use [`Input`](Input.md) for text or identifiers whose leading zeroes and exact characters must be preserved.
@@ -0,0 +1,68 @@
1
+ # PageHeader
2
+
3
+ Open a screen with its title, short context, status and page-level actions. Use one per screen, at the top of `main`.
4
+
5
+ [All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-pageheader--docs)
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import "@kb.ui/react/styles.css";
11
+ import { Badge, Button, Link, PageHeader } from "@kb.ui/react";
12
+
13
+ export function Example() {
14
+ return (
15
+ <main>
16
+ <PageHeader
17
+ navigation={<Link href="/orders">← All orders</Link>}
18
+ eyebrow="Order"
19
+ title="#10482"
20
+ meta={<Badge tone="success">Paid</Badge>}
21
+ description="Placed on 12 October 2026 by Ana Ruiz · 3 items · €184.00"
22
+ actions={
23
+ <>
24
+ <Button variant="secondary">Refund</Button>
25
+ <Button>Fulfil order</Button>
26
+ </>
27
+ }
28
+ />
29
+ </main>
30
+ );
31
+ }
32
+ ```
33
+
34
+ The title renders as an `h1`. Actions sit at the end of the title row. Below 40rem of header width they take their own row under the heading, still end-aligned; wider headers move them below only when the heading's minimum width no longer fits.
35
+
36
+ ## More examples
37
+
38
+ - [Detail with status](https://kbui.kcb.pro/storybook/?path=/story/components-pageheader--detail-with-status): Add a back link, an object-type eyebrow and status badges to a record screen.
39
+ - [Breadcrumbs](https://kbui.kcb.pro/storybook/?path=/story/components-pageheader--breadcrumbs): Place a labelled breadcrumb `nav` in `navigation` for nested settings.
40
+ - [With tabs](https://kbui.kcb.pro/storybook/?path=/story/components-pageheader--with-tabs): Put a `Tabs.List` in the body and draw a divider above the panels.
41
+ - [Sizes](https://kbui.kcb.pro/storybook/?path=/story/components-pageheader--sizes): Choose `sm` for dense app shells and `lg` for landing screens.
42
+ - [Narrow wrap](https://kbui.kcb.pro/storybook/?path=/story/components-pageheader--narrow-wrap): See long titles wrap and actions move below the heading at 320 pixels.
43
+
44
+ ## Reference
45
+
46
+ | Prop | Type | Default | Notes |
47
+ | -------------- | --------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
48
+ | `title` | `ReactNode` | required | Page name, rendered as the heading |
49
+ | `description` | `ReactNode` | unset | One or two sentences of context below the title |
50
+ | `eyebrow` | `ReactNode` | unset | Short section or object-type label above the title |
51
+ | `navigation` | `ReactNode` | unset | Back link or breadcrumb `nav` above the heading |
52
+ | `meta` | `ReactNode` | unset | `Status` badges or metadata beside the title; kept out of the heading's accessible name |
53
+ | `actions` | `ReactNode` | unset | Page-level buttons or links; end-aligned, wrapping below the heading when narrow |
54
+ | `headingLevel` | `1` / `2` / `3` | `1` | Heading rank; lower it only when the header introduces a region below an existing `h1` |
55
+ | `size` | `sm` / `md` / `lg` | `md` | Title scale: `sm` uses the `h2` size, `md` the `h1` size, `lg` the display size |
56
+ | `divider` | `boolean` | `false` | Draws a rule below the header |
57
+ | `children` | `ReactNode` | unset | Header body below the title row, such as a `Tabs.List` or filters |
58
+ | `classNames` | keyed classes | unset | Style `navigation`, `main`, `heading`, `eyebrow`, `headline`, `title`, `meta`, `description`, `actions`, `body` |
59
+
60
+ The root is a `div`, not `header`. A `header` outside `main` or a sectioning element becomes a banner landmark and would compete with the site header. Other native `div` props pass through to the root.
61
+
62
+ Keep one primary action. Put secondary actions before it and move rarely used actions into a [`Menu`](Menu.md).
63
+
64
+ For breadcrumbs, use a labelled `nav` with an ordered list and mark the current item with `aria-current="page"`. Reset list-item margins when using flex layout with `gap`, allow the trail to wrap, and hide decorative separators from assistive technology. Links keep their normal Tab order. See the [breadcrumb example](https://kbui.kcb.pro/storybook/?path=/story/components-pageheader--breadcrumbs) and [WAI breadcrumb pattern](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/).
65
+
66
+ ## Related components
67
+
68
+ Use [`Heading`](Heading.md) for section titles inside the page, [`EmptyState`](EmptyState.md) when the page has no content yet, [`Toolbar`](Toolbar.md) for a dense group of controls that act on the content below, and [`Container`](Container.md) to set the page width the header shares with its content.
@@ -0,0 +1,153 @@
1
+ # Panel
2
+
3
+ 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`.
4
+
5
+ [All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-panel--docs)
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import "@kb.ui/react/styles.css";
11
+ import { Button, Panel } from "@kb.ui/react";
12
+
13
+ export function Example() {
14
+ return (
15
+ <Panel aria-labelledby="queue-title">
16
+ <Panel.Header>
17
+ <h2 id="queue-title">Review queue</h2>
18
+ </Panel.Header>
19
+ <Panel.Body>Three items need review.</Panel.Body>
20
+ <Panel.Footer>
21
+ <Button>Open queue</Button>
22
+ </Panel.Footer>
23
+ </Panel>
24
+ );
25
+ }
26
+ ```
27
+
28
+ ## More examples
29
+
30
+ - [Optional details](https://kbui.kcb.pro/storybook/?path=/story/components-panel--collapsible): Expand and collapse a section from its toggle.
31
+ - [Section actions](https://kbui.kcb.pro/storybook/?path=/story/components-panel--toolbar): Group actions alongside the section heading.
32
+ - [Nested sections](https://kbui.kcb.pro/storybook/?path=/story/components-panel--nested): Inspect depth and grouping inside a parent panel.
33
+ - [Opaque surface](https://kbui.kcb.pro/storybook/?path=/story/components-panel--opaque): Compare a glass panel with one that drops the blur.
34
+
35
+ ## Reference
36
+
37
+ ```tsx
38
+ <Panel tone="active" rail="status" aria-labelledby="queue-title">
39
+ <Panel.Header>
40
+ <h2 id="queue-title">Queue</h2>
41
+ <Panel.Toolbar>
42
+ <Button size="sm">Retry</Button>
43
+ </Panel.Toolbar>
44
+ </Panel.Header>
45
+ <Panel.Body>
46
+ <Panel.Well>…</Panel.Well>
47
+ </Panel.Body>
48
+ <Panel.Footer>…</Panel.Footer>
49
+ </Panel>
50
+ ```
51
+
52
+ | Prop | Values | Default | Notes |
53
+ | -------------- | ------------------------------------------------------ | ------------ | --------------------------------------------------------------------- |
54
+ | `tone` | `quiet` / `default` / `sunken` / `active` / `critical` | `default` | Changes the surface emphasis; pair state colors with explanatory text |
55
+ | `rail` | `none` / `accent` / `status` | `none` | Accent stays the accent color; status follows the current tone |
56
+ | `density` | `compact` / `standard` | `standard` | Changes padding without changing semantics |
57
+ | `opaque` | `boolean` | `false` | Solid fill with no backdrop filter, whatever the theme sets |
58
+ | `collapsible` | `boolean` | `false` | Enables `Panel.Toggle` and collapsible body behavior |
59
+ | `open` | `boolean` | uncontrolled | Current body visibility when collapsible is enabled |
60
+ | `defaultOpen` | `boolean` | `false` | Initial visibility for an uncontrolled collapsible panel |
61
+ | `onOpenChange` | `(open: boolean) => void` | unset | Update open here when your app controls visibility |
62
+
63
+ `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`.
64
+
65
+ 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.
66
+
67
+ `opaque` turns off the theme’s glass for one panel: it drops `--kb-panel-backdrop` and paints the tone fill over the `--kb-panel-background-opaque` base. Use it under content that redraws often, such as a live terminal or log, where a backdrop blur costs memory and compositing work. It fills even a `quiet` panel. Nested panels keep their own glass; give each one that holds live content `opaque` too. Set `--kb-panel-background-opaque` in your theme to change the base; keep it a solid color that contrasts with `--kb-color-fg` in light and dark.
68
+
69
+ ```tsx
70
+ <Panel opaque aria-labelledby="terminal-title">…</Panel>
71
+ ```
72
+
73
+ ## Resizable panels
74
+
75
+ 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.
76
+
77
+ ```tsx
78
+ <Panel.Group direction="row">
79
+ <Panel aria-labelledby="code-title">…</Panel>
80
+ <Panel.Handle aria-label="Resize code" defaultSize={50} min={25} max={75} />
81
+ <Panel aria-labelledby="view-title">…</Panel>
82
+ </Panel.Group>
83
+ ```
84
+
85
+ `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.
86
+
87
+ 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`.
88
+
89
+ ## Related components
90
+
91
+ Use [`Card`](Card.md) for a self-contained item and [`Grid`](Grid.md) or [`Split`](Split.md) to arrange sections.
92
+
93
+ ## Resizing without dragging
94
+
95
+ The handle’s keyboard model supports keyboard access. For users who operate a pointer without dragging, provide controls for the same resizing task. This composition uses the existing controlled size API; the surrounding application supplies named click/tap buttons and feedback after button actions. Assess the chosen range and increments against the task’s required functionality.
96
+
97
+ ```tsx
98
+ import "@kb.ui/react/styles.css";
99
+ import { Button, Inline, Panel, Status } from "@kb.ui/react";
100
+ import { useId, useState } from "react";
101
+
102
+ export function ResizableWorkspace() {
103
+ const titleId = useId();
104
+ const [size, setSize] = useState(50);
105
+ const [message, setMessage] = useState("");
106
+ function resizeBy(amount: number) {
107
+ const next = Math.max(25, Math.min(75, size + amount));
108
+ setSize(next);
109
+ setMessage(`Code panel width ${next} percent.`);
110
+ }
111
+ return (
112
+ <>
113
+ <Inline>
114
+ <Button
115
+ type="button"
116
+ disabled={size <= 25}
117
+ onClick={() => resizeBy(-5)}
118
+ >
119
+ Make code narrower
120
+ </Button>
121
+ <Button type="button" disabled={size >= 75} onClick={() => resizeBy(5)}>
122
+ Make code wider
123
+ </Button>
124
+ <Status live>{message}</Status>
125
+ </Inline>
126
+ <Panel.Group direction="row" style={{ width: "100%", minHeight: 240 }}>
127
+ <Panel aria-labelledby={titleId}>
128
+ <Panel.Header>
129
+ <h2 id={titleId}>Code</h2>
130
+ </Panel.Header>
131
+ <Panel.Body>Editable source content.</Panel.Body>
132
+ </Panel>
133
+ <Panel.Handle
134
+ aria-labelledby={titleId}
135
+ size={size}
136
+ onSizeChange={(next) => {
137
+ setSize(next);
138
+ setMessage("");
139
+ }}
140
+ min={25}
141
+ max={75}
142
+ step={5}
143
+ />
144
+ <Panel aria-label="Preview">
145
+ <Panel.Body>Resulting preview.</Panel.Body>
146
+ </Panel>
147
+ </Panel.Group>
148
+ </>
149
+ );
150
+ }
151
+ ```
152
+
153
+ Click each resize button, then focus the handle and use its arrow keys, Home/End, and Enter. Check that pane width, separator value, disabled limits, focus visibility, and feedback stay correct. Test the actual composition at zoom and with supported assistive technology. See the shared [accessibility verification guide](https://github.com/KhallilB/kbui/blob/main/docs/guides/accessibility.md#keyboard-focus-and-pointer-input) for WCAG 2.5.7 and target-size requirements.
@@ -0,0 +1,89 @@
1
+ # Popover
2
+
3
+ Reveal supporting controls or details in an anchored popup while retaining page context. Base UI owns positioning, focus management and dismissal. Non-modal interaction is the default.
4
+
5
+ [All components](../../README.md#components) · [Usage](#usage) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-popover--docs)
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import "@kb.ui/react/styles.css";
11
+ import { Button, Input, Popover } from "@kb.ui/react";
12
+
13
+ export function ViewOptions() {
14
+ return (
15
+ <Popover>
16
+ <Popover.Trigger render={<Button variant="secondary" />}>View options</Popover.Trigger>
17
+ <Popover.Content title="View options">
18
+ <Popover.Body><Input label="Contains text" /></Popover.Body>
19
+ <Popover.Footer>
20
+ <Popover.Close render={<Button />}>Done</Popover.Close>
21
+ </Popover.Footer>
22
+ </Popover.Content>
23
+ </Popover>
24
+ );
25
+ }
26
+ ```
27
+
28
+ ## More examples
29
+
30
+ - [Display preferences](https://kbui.kcb.pro/storybook/?path=/story/components-popover--default): immediate, reversible changes to the activity list, with Reset and Done.
31
+ - [Controlled editing](https://kbui.kcb.pro/storybook/?path=/story/components-popover--controlled): drafts, Cancel, validation and native Enter submission; only Save commits the new name.
32
+ - [Nested theme](https://kbui.kcb.pro/storybook/?path=/story/components-popover--scoped-portal): portal inside a local theme host.
33
+ - [Inside Dialog](https://kbui.kcb.pro/storybook/?path=/story/components-popover--inside-dialog): nested Escape dismissal and focus recovery.
34
+ - [Scrolling workspace](https://kbui.kcb.pro/storybook/?path=/story/components-popover--scrolling): keep a compact form and its Done action visible while the surrounding workspace scrolls.
35
+
36
+ ## Reference
37
+
38
+ | Part / prop | Type | Default | Purpose |
39
+ |---|---|---|---|
40
+ | `Popover` | Base UI `Popover` root props | — | Groups parts without adding a DOM element. |
41
+ | `open` / `defaultOpen` | `boolean` | `false` | Controlled or initial open state. |
42
+ | `onOpenChange` | `(open, details) => void` | — | Requests opening/dismissal; supports `details.cancel()`. |
43
+ | `modal` | `boolean` or `"trap-focus"` | `false` | Configures interaction containment. Include Close for modal focus containment and touch-screen-reader escape. |
44
+ | `Popover.Trigger` | Base UI `Popover` trigger props | `button` | Supports `Button` composition, refs and native disabled. |
45
+ | `Popover.Content` | Base UI `Popover` popup props | `div` | Portaled interactive popup with ref and native attributes. |
46
+ | `Content.title` / `description` | `ReactNode` | — | Adds associated Title and Description inside Header; omit when composing those parts. |
47
+ | `Content.container` | Base UI portal container | `document.body` | Targets a stable theme host, including refs. |
48
+ | `Content.side` / `align` | Base UI positioner values | `bottom` / `start` | Preferred placement; collision handling may adjust it. |
49
+ | `Content.sideOffset` | Base UI side offset | `6` | Gap from trigger in CSS pixels. |
50
+ | `Content.positionerProps` | Base UI positioner props | — | Advanced collision boundary/padding, offsets, custom anchor, styles and ref; excludes children, `className`, side, align and `sideOffset`. |
51
+ | `Content.initialFocus` / `finalFocus` | Base UI focus target | Primitive defaults | Customize entry and return focus; supports refs and callbacks. |
52
+ | `Content.className` | `string` | — | Additional popup class. |
53
+ | `Content.classNames` | `{ positioner?: string }` | — | Additional class on positioning wrapper. |
54
+ | `Popover.Title` / `Description` | Base UI naming part props | — | Compose accessible names and descriptions; accepts string `className` and refs. |
55
+ | `Popover.Header` / `Body` / `Footer` | Native `div` props and refs | `div` | Header and Footer stay outside Body scrolling. Body must be a direct Content child; Footer holds visible actions. |
56
+ | `Popover.Close` | Base UI close props | `button` | Dismisses without performing an application action. |
57
+
58
+ Name every popup with title, Title or `aria-label`. Include a visible Close action, especially for touch and modal usage. Escape closes the popup and restores focus; a non-modal outside press dismisses while allowing outside interaction. Default keyboard opening focuses the first tabbable control or the popup; touch opening can focus the popup to avoid launching a virtual keyboard. Keep required instructions available outside temporary content.
59
+
60
+ Keep popovers short: show the relevant controls and a visible Done/Close action together. Avoid artificial height caps, large descriptions or long lists of secondary content. Use `Dialog`, Drawer or inline `Disclosure` when a task needs more room.
61
+
62
+ For constrained viewports, compose direct Header, Body and Footer children. Content title/description props create Header automatically. Only Body shrinks and scrolls; Footer actions and the heading stay visible. A long scrollable Body needs a name and `tabIndex={0}` for keyboard scrolling; keep essential instructions and actions outside it. The outer popup can still scroll as a fallback when enlarged header/footer content alone exceeds available space. The popup fits the positioning engine's available width/height. `positionerProps` retains Base UI collision and anchor configuration. Set `container` for nested themes and keep the host outside clipping/transformed ancestors when needed. See [theme hosts and portals](../../../../docs/guides/forms-and-overlays.md#theme-hosts-and-portals).
63
+
64
+ Style `--kb-popover-width`, `-padding`, `-background`, `-color`, `-border`, `-radius` and `-shadow`. `--kb-popover-motion-duration`, `-motion-easing`, `-enter-scale` and `-enter-offset` control anchored motion; reduced motion disables transitions and movement. Position changes track scrolling immediately. Change theme-dependent aliases on the appropriate portal host.
65
+
66
+ ## Interaction patterns
67
+
68
+ Use an explicit button with a descriptive label. A decorative chevron can show that it reveals controls; preserve the trigger's expanded state and native Enter/Space handling. Open by click, tap or keyboard activation. Keep non-modal controls in normal Tab order and provide a visible dismissal action. Escape returns focus to the trigger; outside press dismisses without blocking the surrounding page. Base UI owns these behaviors and adapts touch focus to avoid opening a virtual keyboard unnecessarily.
69
+
70
+ Choose one update model and explain it:
71
+
72
+ | Task | Update model | Actions and dismissal |
73
+ |---|---|---|
74
+ | View preferences | Apply immediately; show the effect in surrounding content. | Reset restores defaults; Done, Escape and outside press retain the chosen settings. |
75
+ | Edit a value | Keep a separate draft until valid submission. | Save/Enter commits; Cancel, Escape and outside press discard the draft. Reopening starts from the saved value. |
76
+
77
+ The Default and Controlled stories implement these two models. Do not label a dismiss-only button Save, and do not silently commit a draft on outside dismissal. Keep asynchronous operations and error recovery application-owned.
78
+
79
+ Test the actual embedding viewport. A portal escapes DOM clipping but cannot escape an iframe's viewport. Leave space around the trigger for the complete panel and its actions; a tiny host must offer a larger preview or compose `Dialog`/Drawer. Do not accept a Body that collapses to zero height while a field technically remains in the accessibility tree. Catalog previews reserve the popup footprint and open the real panel at mobile/desktop widths, including paired themes.
80
+
81
+ Follow the [Base UI focus/positioning contract](https://base-ui.com/react/components/popover) and [WAI non-modal dialog guidance](https://www.w3.org/TR/wai-aria-1.2/#dialog). For complex tasks on compact screens, use an explicit sheet/dialog composition and preserve its modal semantics rather than changing modes during an open interaction.
82
+
83
+ ## Verification limits
84
+
85
+ Run `bun run test:overlays` for Chromium, Firefox and WebKit checks in both themes and motion preferences. Scans exclude only Base UI’s implementation focus guards, following maintainer guidance; real controls retain naming checks. Native keyboard and scanner negative-control regressions protect that boundary. See [overlay verification](../../../../docs/guides/accessibility.md#overlay-compatibility) for the policy and manual screen-reader assessment limits.
86
+
87
+ ## Related components
88
+
89
+ Use [`Tooltip`](Tooltip.md) for brief non-interactive hints, [`Menu`](Menu.md) for action lists, [`Disclosure`](Disclosure.md) for inline details, and [`Dialog`](Dialog.md) for modal tasks and the documented drawer/confirmation patterns.
@@ -0,0 +1,37 @@
1
+ # Progress
2
+
3
+ Show how much of a known task is complete. Use a task label rather than a percentage as the accessible name.
4
+
5
+ [All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-progress--docs)
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import "@kb.ui/react/styles.css";
11
+ import { Progress } from "@kb.ui/react";
12
+
13
+ export function Example() {
14
+ return <Progress label="Upload progress" value={60} />;
15
+ }
16
+ ```
17
+
18
+ ## More examples
19
+
20
+ - [Counted work](https://kbui.kcb.pro/storybook/?path=/story/components-progress--steps): Present a readable completed/total value.
21
+ - [Completed work](https://kbui.kcb.pro/storybook/?path=/story/components-progress--complete): Inspect the final state.
22
+
23
+ ## Reference
24
+
25
+ | Prop | Type | Default | Notes |
26
+ | ------------ | ------------- | -------------------- | ----------------------------------------------------------- |
27
+ | `label` | `ReactNode` | required | Visible task name and accessible progressbar label |
28
+ | `value` | `number` | required | Completed amount, from zero to max |
29
+ | `max` | `number` | `100` | Total amount; set it for counts such as three of five steps |
30
+ | `valueText` | `string` | formatted percentage | Visible and announced value, such as 3 of 5 files |
31
+ | `classNames` | keyed classes | unset | Style head, label, value, track, or indicator |
32
+
33
+ The current value stays available to assistive technology. Your app owns task completion and any separate completion announcement.
34
+
35
+ ## Related components
36
+
37
+ Use [`Status`](Status.md) for a textual state and [`Stat`](Stat.md) for a headline measure without completion semantics.
@@ -0,0 +1,69 @@
1
+ # RadioGroup
2
+
3
+ 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.
4
+
5
+ [All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-radiogroup--docs)
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import "@kb.ui/react/styles.css";
11
+ import { RadioGroup } from "@kb.ui/react";
12
+ import { useState } from "react";
13
+
14
+ export function Example() {
15
+ const [value, setValue] = useState<string | null>("weekly");
16
+ return (
17
+ <RadioGroup label="Frequency" value={value} onValueChange={setValue}>
18
+ <RadioGroup.Item value="daily">Daily</RadioGroup.Item>
19
+ <RadioGroup.Item value="weekly">Weekly</RadioGroup.Item>
20
+ </RadioGroup>
21
+ );
22
+ }
23
+ ```
24
+
25
+ ## More examples
26
+
27
+ - [An unanswered choice](https://kbui.kcb.pro/storybook/?path=/story/components-radiogroup--empty-selection): Start without a selected option.
28
+ - [Segmented choices](https://kbui.kcb.pro/storybook/?path=/story/components-radiogroup--segmented): Show a compact layout with the same single-choice behavior.
29
+ - [Validation feedback](https://kbui.kcb.pro/storybook/?path=/story/components-radiogroup--invalid): Explain why a choice is required.
30
+
31
+ ## Reference
32
+
33
+ | Prop | Type | Default | Notes |
34
+ | ----------------------- | --------------------------- | ------------ | -------------------------------------------------------- |
35
+ | `label` | `string` | required | Visible accessible group label |
36
+ | `value` | `string \| null` | required | Controlled choice; null means no choice |
37
+ | `onValueChange` | `(value: string) => void` | required | Next choice request |
38
+ | `appearance` | `"standard" \| "segmented"` | `"standard"` | Segmented tray for compact single-choice controls |
39
+ | `selectionMotion` | `"slide" \| "none"` | `"slide"` | Segmented selection background glides or moves instantly |
40
+ | `selectionTone` | `"primary" \| "neutral"` | `"primary"` | Accent pill by default; neutral uses the raised surface |
41
+ | `disabled` | `boolean` | `false` | Disable every item |
42
+ | `name` | `string` | | Native form field name |
43
+ | `description` / `error` | `string` | | Associated help and invalid-state text |
44
+ | `visuallyHidden` | `boolean` | `false` | Hide group label visually |
45
+ | `ref` | `Ref<HTMLDivElement>` | | Group root |
46
+
47
+ ```tsx
48
+ <RadioGroup
49
+ label="Density"
50
+ name="density"
51
+ value={density}
52
+ onValueChange={setDensity}
53
+ >
54
+ <RadioGroup.Item value="compact">Compact</RadioGroup.Item>
55
+ <RadioGroup.Item value="comfortable">Comfortable</RadioGroup.Item>
56
+ </RadioGroup>
57
+ ```
58
+
59
+ `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`.
60
+
61
+ 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.
62
+
63
+ 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.
64
+
65
+ 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.
66
+
67
+ ## Related components
68
+
69
+ Use [`Checkbox`](Checkbox.md) for independent choices and [`Select`](Select.md) when the options belong in a dropdown.
@@ -0,0 +1,40 @@
1
+ # ScrollArea
2
+
3
+ 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.
4
+
5
+ [All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-scrollarea--docs)
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import "@kb.ui/react/styles.css";
11
+ import { ScrollArea } from "@kb.ui/react";
12
+
13
+ export function Example() {
14
+ return (
15
+ <ScrollArea label="Activity log" maxHeight="12rem">
16
+ <p>Project created.</p>
17
+ <p>Review requested.</p>
18
+ </ScrollArea>
19
+ );
20
+ }
21
+ ```
22
+
23
+ ## More examples
24
+
25
+ - [Keyboard scrolling](https://kbui.kcb.pro/storybook/?path=/story/components-scrollarea--default): Focus the named scrolling region and try the keyboard.
26
+
27
+ ## Reference
28
+
29
+ | Prop | Type | Default | Notes |
30
+ | ------------ | ----------------- | -------- | ------------------------------------------------- |
31
+ | `label` | `string` | required | Accessible name of the focusable scrolling region |
32
+ | `children` | `ReactNode` | required | Content inside the viewport |
33
+ | `maxHeight` | CSS length string | unset | Height cap, such as 12rem; longer content scrolls |
34
+ | `classNames` | keyed classes | unset | Style viewport, scrollbar, or thumb |
35
+
36
+ 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.
37
+
38
+ ## Related components
39
+
40
+ Use [`Panel`](Panel.md) to group the scrolling content with its heading and actions.
@@ -0,0 +1,71 @@
1
+ # Select
2
+
3
+ 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.
4
+
5
+ [All components](../../README.md#components) · [Usage](#usage) · [Examples](#more-examples) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-select--docs)
6
+
7
+ ## Usage
8
+
9
+ ```tsx
10
+ import "@kb.ui/react/styles.css";
11
+ import { Select } from "@kb.ui/react";
12
+ import { useState } from "react";
13
+
14
+ export function Example() {
15
+ const [value, setValue] = useState<string | null>(null);
16
+ return (
17
+ <Select
18
+ label="Frequency"
19
+ value={value}
20
+ onValueChange={setValue}
21
+ options={[
22
+ { value: "daily", label: "Daily" },
23
+ { value: "weekly", label: "Weekly" },
24
+ ]}
25
+ />
26
+ );
27
+ }
28
+ ```
29
+
30
+ ## More examples
31
+
32
+ - [No available options](https://kbui.kcb.pro/storybook/?path=/story/components-select--empty): Inspect the empty helper and field description.
33
+ - [Validation feedback](https://kbui.kcb.pro/storybook/?path=/story/components-select--invalid): Explain a selection that needs correction.
34
+ - [A retained selection](https://kbui.kcb.pro/storybook/?path=/story/components-select--read-only): Keep the chosen value while preventing changes.
35
+
36
+ ## Reference
37
+
38
+ | Prop | Type | Default | Notes |
39
+ | ------------------------------------- | ---------------------------------- | -------------------- | --------------------------------------------------------- |
40
+ | `label` | `string` | required | Visible field label and accessible popup name |
41
+ | `value` | `string \| null` | required | Controlled selection; null means unset |
42
+ | `onValueChange` | `(value: string \| null) => void` | required | Next valid choice request |
43
+ | `options` | `readonly SelectOption[]` | required | Ordered unique values, labels and optional disabled flags |
44
+ | `placeholder` | `string` | `"Choose an option"` | Text for unset values |
45
+ | `description` / `error` | `string` | | Associated help and invalid-state text |
46
+ | `disabled` / `readOnly` | `boolean` | `false` | Prevent edits; disabled also blocks form submission |
47
+ | `name` | `string` | | Native hidden form field name |
48
+ | `container` | `Select.Portal.Props["container"]` | field root | Portal host; default retains nested theme |
49
+ | `controlClassName` / `popupClassName` | `string` | | Trigger and popup slot classes |
50
+ | `className` / `ref` | root div props | | Wrapper class and native root ref |
51
+
52
+ ```tsx
53
+ <Select
54
+ label="View"
55
+ name="view"
56
+ value={view}
57
+ onValueChange={setView}
58
+ options={[
59
+ { value: "recent", label: "Recent" },
60
+ { value: "all", label: "All records" },
61
+ ]}
62
+ />
63
+ ```
64
+
65
+ 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.
66
+
67
+ 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.
68
+
69
+ ## Related components
70
+
71
+ Use [`RadioGroup`](RadioGroup.md) for a visible set of choices and [`Menu`](Menu.md) for actions.