@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.
- package/README.md +142 -707
- package/dist/components/Accordion/Accordion.d.ts +33 -0
- package/dist/components/Avatar/Avatar.d.ts +19 -0
- package/dist/components/Code/Code.d.ts +26 -3
- package/dist/components/Code/tokenize.d.ts +5 -0
- package/dist/components/CodeBlock/CodeBlock.d.ts +10 -0
- package/dist/components/Collection/Collection.d.ts +99 -0
- package/dist/components/Collection/useCollection.d.ts +66 -0
- package/dist/components/CollectionList/CollectionList.d.ts +12 -0
- package/dist/components/CollectionRow/CollectionRow.d.ts +17 -0
- package/dist/components/Combobox/Combobox.d.ts +14 -2
- package/dist/components/ConfirmAction/ConfirmAction.d.ts +42 -0
- package/dist/components/CopyableText/CopyableText.d.ts +38 -0
- package/dist/components/CopyableText/content.d.ts +14 -0
- package/dist/components/Dashboard/Dashboard.d.ts +17 -0
- package/dist/components/DescriptionList/DescriptionList.d.ts +20 -0
- package/dist/components/Dialog/Dialog.d.ts +3 -1
- package/dist/components/Disclosure/Disclosure.d.ts +21 -0
- package/dist/components/EmptyState/EmptyState.d.ts +30 -0
- package/dist/components/Form/Form.d.ts +19 -0
- package/dist/components/FormSection/FormSection.d.ts +26 -0
- package/dist/components/Gallery/Gallery.d.ts +26 -0
- package/dist/components/Grid/Grid.d.ts +17 -6
- package/dist/components/Image/Image.d.ts +20 -0
- package/dist/components/Link/Link.d.ts +15 -2
- package/dist/components/PageHeader/PageHeader.d.ts +27 -0
- package/dist/components/Panel/Panel.d.ts +3 -1
- package/dist/components/Popover/Popover.d.ts +55 -0
- package/dist/components/Settings/Settings.d.ts +11 -0
- package/dist/components/Skeleton/Skeleton.d.ts +34 -0
- package/dist/components/Spinner/Spinner.d.ts +26 -0
- package/dist/components/Stack/Stack.d.ts +15 -0
- package/dist/components/StatsRow/StatsRow.d.ts +33 -0
- package/dist/components/SupportingPane/SupportingPane.d.ts +15 -0
- package/dist/components/Table/Table.d.ts +65 -0
- package/dist/components/Tabs/Tabs.d.ts +69 -0
- package/dist/components/Tabs/index.d.ts +1 -0
- package/dist/components/Thumbnail/Thumbnail.d.ts +14 -0
- package/dist/components/Toast/Toast.d.ts +72 -0
- package/dist/index.d.ts +39 -4
- package/dist/index.js +3901 -1238
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/utils/CollapsiblePanel.d.ts +10 -0
- package/dist/utils/useClipboard.d.ts +28 -0
- package/docs/components/Accordion.md +66 -0
- package/docs/components/Avatar.md +80 -0
- package/docs/components/Badge.md +37 -0
- package/docs/components/Button.md +46 -0
- package/docs/components/Callout.md +41 -0
- package/docs/components/Card.md +41 -0
- package/docs/components/Checkbox.md +60 -0
- package/docs/components/Code.md +77 -0
- package/docs/components/CodeBlock.md +77 -0
- package/docs/components/Collection.md +183 -0
- package/docs/components/CollectionList.md +44 -0
- package/docs/components/CollectionRow.md +62 -0
- package/docs/components/Combobox.md +88 -0
- package/docs/components/ConfirmAction.md +100 -0
- package/docs/components/Container.md +41 -0
- package/docs/components/CopyableText.md +93 -0
- package/docs/components/Dashboard.md +81 -0
- package/docs/components/DescriptionList.md +61 -0
- package/docs/components/Dialog.md +84 -0
- package/docs/components/Disclosure.md +53 -0
- package/docs/components/EmptyState.md +50 -0
- package/docs/components/ErrorSummary.md +48 -0
- package/docs/components/Fieldset.md +42 -0
- package/docs/components/FileInput.md +74 -0
- package/docs/components/Form.md +67 -0
- package/docs/components/FormActions.md +45 -0
- package/docs/components/FormSection.md +57 -0
- package/docs/components/Gallery.md +84 -0
- package/docs/components/Grid.md +66 -0
- package/docs/components/Heading.md +40 -0
- package/docs/components/Image.md +62 -0
- package/docs/components/Inline.md +42 -0
- package/docs/components/Input.md +82 -0
- package/docs/components/Link.md +52 -0
- package/docs/components/Menu.md +44 -0
- package/docs/components/MultiSelect.md +59 -0
- package/docs/components/NumberField.md +65 -0
- package/docs/components/PageHeader.md +68 -0
- package/docs/components/Panel.md +153 -0
- package/docs/components/Popover.md +89 -0
- package/docs/components/Progress.md +37 -0
- package/docs/components/RadioGroup.md +69 -0
- package/docs/components/ScrollArea.md +40 -0
- package/docs/components/Select.md +71 -0
- package/docs/components/Separator.md +40 -0
- package/docs/components/Settings.md +57 -0
- package/docs/components/Skeleton.md +86 -0
- package/docs/components/Spinner.md +45 -0
- package/docs/components/Split.md +47 -0
- package/docs/components/Stack.md +54 -0
- package/docs/components/Stat.md +34 -0
- package/docs/components/StatsRow.md +80 -0
- package/docs/components/Status.md +48 -0
- package/docs/components/SupportingPane.md +59 -0
- package/docs/components/Switch.md +73 -0
- package/docs/components/Table.md +105 -0
- package/docs/components/Tabs.md +89 -0
- package/docs/components/Text.md +36 -0
- package/docs/components/Textarea.md +47 -0
- package/docs/components/Thumbnail.md +66 -0
- package/docs/components/Toast.md +130 -0
- package/docs/components/Toolbar.md +39 -0
- package/docs/components/Tooltip.md +42 -0
- package/package.json +3 -2
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# FormSection
|
|
2
|
+
|
|
3
|
+
Use `FormSection` to group related fields under a section heading, with optional help, a section error and the section's own actions. It renders a native `fieldset` named by its heading, so screen reader users can browse sections by heading and hear the group name on entry. Use [`Form`](Form.md) or [`Settings`](Settings.md) to arrange several sections.
|
|
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-formsection--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, FormSection, Input } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<form onSubmit={(event) => event.preventDefault()}>
|
|
16
|
+
<FormSection
|
|
17
|
+
title="Profile"
|
|
18
|
+
description="Shown to everyone in your workspace."
|
|
19
|
+
actions={<Button type="submit">Save profile</Button>}
|
|
20
|
+
>
|
|
21
|
+
<Input label="Display name" name="name" />
|
|
22
|
+
<Input label="Job title" name="title" />
|
|
23
|
+
</FormSection>
|
|
24
|
+
</form>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## More examples
|
|
30
|
+
|
|
31
|
+
- [Heading beside fields](https://kbui.kcb.pro/storybook/?path=/story/components-formsection--split-layout): `Split` layout, which stacks below 40rem of section width.
|
|
32
|
+
- [Section error](https://kbui.kcb.pro/storybook/?path=/story/components-formsection--section-error): A group-level error alongside a field error.
|
|
33
|
+
- [Pending save](https://kbui.kcb.pro/storybook/?path=/story/components-formsection--pending-save): Lock every field and action while a save is in flight.
|
|
34
|
+
|
|
35
|
+
## Reference
|
|
36
|
+
|
|
37
|
+
| Prop | Type | Default | Notes |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| `title` | `ReactNode` | required | Section heading; also names the group |
|
|
40
|
+
| `headingLevel` | `2 \| 3 \| 4 \| 5 \| 6` | `2` | Heading rank; follow the page outline |
|
|
41
|
+
| `description` | `ReactNode` | unset | Help text; added to the group's `aria-describedby` |
|
|
42
|
+
| `error` | `ReactNode` | unset | Section error; sets `data-invalid` and `aria-invalid` and describes the group |
|
|
43
|
+
| `actions` | `ReactNode` | unset | Buttons rendered in [`FormActions`](FormActions.md) after the fields |
|
|
44
|
+
| `actionsAlign` | `"start" \| "end" \| "between"` | `"end"` | Alignment of the actions row |
|
|
45
|
+
| `layout` | `"stack" \| "split"` | unset | Heading above or beside the fields; unset stacks, or splits inside `Settings` |
|
|
46
|
+
| `disabled` | `boolean` | `false` | Native fieldset disabling for every field and action |
|
|
47
|
+
| `classNames` | `{ header?, title?, description?, body?, fields?, error?, actions? }` | unset | Classes for inner parts |
|
|
48
|
+
|
|
49
|
+
Other native `fieldset` props and `ref` pass through. A caller `aria-describedby` follows the description and error ids, and a caller `aria-invalid` token such as `"spelling"` is kept. The section heading names the group with `aria-labelledby`, unless you pass `aria-label`: a native `legend` cannot sit in the split layout's first column.
|
|
50
|
+
|
|
51
|
+
`Split` layout puts the header in one third and the fields in two thirds when the section is at least `--kb-formsection-collapse` (40rem) wide, and stacks them below that. Actions sit last in the section body, end-aligned. Below 30rem of row width, each button or link in the actions fills its own row so targets stay wide on phones; other content, such as a spinner, keeps its size. Tokens: `--kb-formsection-gap`, `--kb-formsection-header-gap`, `--kb-formsection-fields-gap` and `--kb-formsection-collapse`.
|
|
52
|
+
|
|
53
|
+
Your app owns validation, saving and the announcement of saved or failed sections. While saving, pass `disabled` and `aria-busy`. Native disabling takes focus away from the pressed Save button, so move focus to a status message outside the section (`role="status"`, `tabIndex={-1}`) and report the result there.
|
|
54
|
+
|
|
55
|
+
## Related components
|
|
56
|
+
|
|
57
|
+
Use [`Fieldset`](Fieldset.md) for a question-style group with a legend inside a section, [`FormActions`](FormActions.md) for a form-wide action row and [`ErrorSummary`](ErrorSummary.md) for recovery after a failed submit.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Gallery
|
|
2
|
+
|
|
3
|
+
Use `Gallery` for a page of image-led items, such as a product catalog, a portfolio or a media library. It is the page frame, up to 80rem wide, with a header region, an optional filters region and the items as a list, with one to four columns as the gallery widens. For records you scan by text, use [`CollectionList`](CollectionList.md) or [`Table`](Table.md); for a handful of metrics or links, use [`Grid`](Grid.md).
|
|
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/layout-gallery--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, Card, Gallery, Grid, Heading, Image, Input, PageHeader, Text } from "@kb.ui/react";
|
|
12
|
+
import { useState } from "react";
|
|
13
|
+
|
|
14
|
+
const products = [
|
|
15
|
+
{ id: "classic", name: "The Schu Classic", price: 89, src: "/schu-classic.jpg", alt: "Sage knit sneaker with a white sole" },
|
|
16
|
+
{ id: "trail", name: "The Schu Trail", price: 99, src: "/schu-trail.jpg", alt: "Charcoal knit sneaker with an amber sole" },
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
export function Example() {
|
|
20
|
+
const [query, setQuery] = useState("");
|
|
21
|
+
const visible = products.filter((product) => product.name.toLowerCase().includes(query.toLowerCase()));
|
|
22
|
+
return (
|
|
23
|
+
<main>
|
|
24
|
+
<Gallery
|
|
25
|
+
header={<PageHeader title="Sneakers" description="Our own model beside the brands you love." />}
|
|
26
|
+
filters={
|
|
27
|
+
<>
|
|
28
|
+
<Input label="Search" type="search" value={query} onChange={(event) => setQuery(event.currentTarget.value)} />
|
|
29
|
+
<Text role="status" size="sm" tone="muted">
|
|
30
|
+
{visible.length === 1 ? "1 sneaker" : `${visible.length} sneakers`}
|
|
31
|
+
</Text>
|
|
32
|
+
</>
|
|
33
|
+
}
|
|
34
|
+
itemsLabel="Sneakers"
|
|
35
|
+
empty={<Text>No sneakers match your search.</Text>}
|
|
36
|
+
>
|
|
37
|
+
{visible.map((product, index) => (
|
|
38
|
+
<Gallery.Item key={product.id} featured={index === 0}>
|
|
39
|
+
<Card aria-labelledby={`${product.id}-name`}>
|
|
40
|
+
<Grid layout="stack" gap="sm">
|
|
41
|
+
<Image src={product.src} alt={product.alt} ratio={index === 0 ? "wide" : "landscape"} loading="lazy" />
|
|
42
|
+
<Heading level={2} size="sm" id={`${product.id}-name`}>
|
|
43
|
+
{product.name}
|
|
44
|
+
</Heading>
|
|
45
|
+
<Text>${product.price}</Text>
|
|
46
|
+
<Button variant="secondary">
|
|
47
|
+
Add to cart<span className="kb-sr-only">, {product.name}</span>
|
|
48
|
+
</Button>
|
|
49
|
+
</Grid>
|
|
50
|
+
</Card>
|
|
51
|
+
</Gallery.Item>
|
|
52
|
+
))}
|
|
53
|
+
</Gallery>
|
|
54
|
+
</main>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## More examples
|
|
60
|
+
|
|
61
|
+
- [Product catalog](https://kbui.kcb.pro/storybook/?path=/story/layout-gallery--product-catalog): A sneaker shop that features its own model, with search, brand and sort filters.
|
|
62
|
+
- [No results](https://kbui.kcb.pro/storybook/?path=/story/layout-gallery--no-results): The empty region replaces the list until the filters are cleared.
|
|
63
|
+
- [Inspection](https://kbui.kcb.pro/storybook/?path=/story/layout-gallery--inspection): Square thumbnails that open a full, uncropped preview in a `Dialog`.
|
|
64
|
+
|
|
65
|
+
## Reference
|
|
66
|
+
|
|
67
|
+
| Part / prop | Type | Default | Notes |
|
|
68
|
+
| --- | --- | --- | --- |
|
|
69
|
+
| `header` | `ReactNode` | unset | Page title, intro and actions; usually a `PageHeader` |
|
|
70
|
+
| `filters` | `ReactNode` | unset | Search, filter and sort controls and a result count |
|
|
71
|
+
| `itemsLabel` | `string` | unset | Accessible name for the item list |
|
|
72
|
+
| `empty` | `ReactNode` | unset | Shown in place of the list when there are no items |
|
|
73
|
+
| `classNames` | `{ header?, filters?, items?, empty? }` | unset | Classes for the regions |
|
|
74
|
+
| `Gallery.Item` | native `li` props | `li` | One item; `featured` spans two columns once the list has two |
|
|
75
|
+
|
|
76
|
+
Other native `div` props and `ref` pass through to the root; `Gallery.Item` forwards its own. The items region is a [`Grid`](Grid.md) rendered as `ul`, so wrap every item in `Gallery.Item`.
|
|
77
|
+
|
|
78
|
+
Placement is fixed in the stylesheet and measured on the gallery's own width, not the viewport: one column below 30rem, two from 30rem, three from 48rem and four from 64rem. Filters share a row, each at least 12rem wide, and wrap below it. Item content stretches to the row height; spacing inside an item belongs to its content, such as a stacked `Grid`. Pass items directly or inside fragments: a component that renders no items still counts as one, so `empty` cannot replace the list. Put featured items first: the list keeps DOM order and does not backfill gaps. `Gallery` is also the page frame: it fills its parent up to 80rem, centred, with gutters of 1rem, then 1.5rem from 48rem and 2rem from 64rem of viewport width, so do not wrap it in a [`Container`](Container.md). Tokens: `--kb-gallery-max-width`, `--kb-gallery-gutter-sm`, `--kb-gallery-gutter-md`, `--kb-gallery-gutter-lg`, `--kb-gallery-gap`, `--kb-gallery-filters-gap` and `--kb-gallery-filter-min-width`.
|
|
79
|
+
|
|
80
|
+
Give every meaningful image an `alt` that says what differs between items, such as colour or material; repeat nothing the item heading already says. Name each item with its heading and include that name in item actions. Announce result counts after filtering with a status message, and when a recovery action such as "Clear filters" removes the empty region, move focus to the control it reset. Your app owns data, filtering, pagination and cart state.
|
|
81
|
+
|
|
82
|
+
## Related components
|
|
83
|
+
|
|
84
|
+
Frame media with [`Image`](Image.md) or [`Thumbnail`](Thumbnail.md), open the page with [`PageHeader`](PageHeader.md), show an empty result with [`EmptyState`](EmptyState.md) and inspect an item in a [`Dialog`](Dialog.md).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Grid
|
|
2
|
+
|
|
3
|
+
Arrange cards or other content in responsive columns, fixed column counts, or a single vertical stack. `Grid` uses ordinary CSS layout, without an ARIA grid role or special keyboard navigation, and resets native list markers and margins when rendered as `ul` or `ol`.
|
|
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/layout-grid--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Card, Grid } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<Grid as="ul" role="list" columns={2} gap="md" aria-label="Projects">
|
|
16
|
+
<Card as="li">
|
|
17
|
+
<h2>First project</h2>
|
|
18
|
+
<p>Ready for review.</p>
|
|
19
|
+
</Card>
|
|
20
|
+
<Card as="li">
|
|
21
|
+
<h2>Second project</h2>
|
|
22
|
+
<p>In progress.</p>
|
|
23
|
+
</Card>
|
|
24
|
+
</Grid>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## More examples
|
|
30
|
+
|
|
31
|
+
- [Fixed column counts](https://kbui.kcb.pro/storybook/?path=/story/layout-grid--columns): Compare one through four equal columns.
|
|
32
|
+
- [Responsive minimum widths](https://kbui.kcb.pro/storybook/?path=/story/layout-grid--column-widths): Compare automatic wrapping at different minimum item widths.
|
|
33
|
+
- [Gaps and alignment](https://kbui.kcb.pro/storybook/?path=/story/layout-grid--gaps-and-alignment): Compare spacing presets and cross-axis alignment.
|
|
34
|
+
- [A vertical collection](https://kbui.kcb.pro/storybook/?path=/story/layout-grid--stacked-list): Keep list structure while stacking items.
|
|
35
|
+
|
|
36
|
+
## Reference
|
|
37
|
+
|
|
38
|
+
| Prop | Type | Default | Notes |
|
|
39
|
+
| --------------------------- | --------------------------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
40
|
+
| `as` | `div` / `ul` / `ol` | `div` | Use ul or ol for a collection; children must then be list items |
|
|
41
|
+
| `layout` | `auto` / `stack` | `auto` | Auto fits equal columns to available width; stack uses one column |
|
|
42
|
+
| `columns` | `auto` / `1` / `2` / `3` / `4` | `auto` | Explicit equal column count (collapsing to 1 when the grid is narrower than 30rem) or automatic wrapping |
|
|
43
|
+
| `minItemWidth` | `sm` / `md` / `lg` | `md` | Minimum width (`14rem`, `18.75rem`, `24rem`) before automatic columns wrap |
|
|
44
|
+
| `gap` | `none` / `sm` / `md` / `lg` | `lg` (`--kb-grid-gap`) | Space between columns and stacked rows |
|
|
45
|
+
| `align` | `start` / `center` / `end` / `baseline` / `stretch` | `stretch` | Cross-axis alignment within each grid row |
|
|
46
|
+
| `children` | `ReactNode` | unset | Content in document and keyboard order |
|
|
47
|
+
| `className`, `style`, `ref` | native element props | unset | Style and reference the chosen container |
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<Grid as="ul" role="list" layout="stack" gap="md" aria-label="Projects">
|
|
51
|
+
<Card as="li">
|
|
52
|
+
<h2>
|
|
53
|
+
<a href="/project">Project</a>
|
|
54
|
+
</h2>
|
|
55
|
+
<p>Summary</p>
|
|
56
|
+
</Card>
|
|
57
|
+
</Grid>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Use `minItemWidth`, `columns`, `gap`, and `align` for common layouts, or override `--kb-grid-gap` and `--kb-grid-min-item-width` (`-sm`, `-md`, `-lg`) on a subtree. Keep the visual order the same as the reading order.
|
|
61
|
+
|
|
62
|
+
`Grid` removes list markers. Include `role="list"` on list renderings to retain list exposure in Safari when `list-style: none` is applied; see [MDN’s list-style accessibility guidance](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/list-style#accessibility). Confirm list/item announcement with your supported browser and screen reader.
|
|
63
|
+
|
|
64
|
+
## Related components
|
|
65
|
+
|
|
66
|
+
Use [`Split`](Split.md) for exactly two weighted columns, [`Inline`](Inline.md) for a wrapping row of independent items, and [`Stack`](Stack.md) for vertical flow that never forms columns.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Heading
|
|
2
|
+
|
|
3
|
+
Native `h1`–`h6` headings with visual size independent of rank.
|
|
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-heading--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Heading } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<Heading level={1} size="lg">
|
|
16
|
+
Project overview
|
|
17
|
+
</Heading>
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## More examples
|
|
23
|
+
|
|
24
|
+
- [Document hierarchy](https://kbui.kcb.pro/storybook/?path=/story/components-heading--hierarchy): Compare semantic heading ranks.
|
|
25
|
+
- [Visual hierarchy](https://kbui.kcb.pro/storybook/?path=/story/components-heading--sizes): Compare sizes separately from heading rank.
|
|
26
|
+
- [A complete article](https://kbui.kcb.pro/storybook/?path=/story/components-heading--article): Combine `Heading`, `Text`, `Link`, and `Code`.
|
|
27
|
+
|
|
28
|
+
## Reference
|
|
29
|
+
|
|
30
|
+
| Prop | Type | Default | Notes |
|
|
31
|
+
| ------------------ | ----------------------------------------- | ---------- | -------------------------------------------------------------------------- |
|
|
32
|
+
| `level` | `1` \| `2` \| `3` \| `4` \| `5` \| `6` | `2` | Document rank; choose from page structure |
|
|
33
|
+
| `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 |
|
|
34
|
+
| `className`, `ref` | Native heading props | unset | Classes merge; ref targets native heading |
|
|
35
|
+
|
|
36
|
+
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](https://github.com/KhallilB/kbui/blob/main/docs/guides/typography.md) for composition, CSS recipes and accessibility guidance.
|
|
37
|
+
|
|
38
|
+
## Related components
|
|
39
|
+
|
|
40
|
+
Pair with [`Text`](Text.md), [`Link`](Link.md), and [`Code`](Code.md) for readable document content.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Image
|
|
2
|
+
|
|
3
|
+
Reserve a stable frame for images, with crop, contain and fallback states. The same accessible alternative remains available while loading and after failure.
|
|
4
|
+
|
|
5
|
+
[All components](../../README.md#components) · [Usage](#usage) · [Reference](#reference) · [Live examples and accessibility](https://kbui.kcb.pro/storybook/?path=/docs/components-image--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Image } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<Image
|
|
16
|
+
src="/products/studio-coat.jpg"
|
|
17
|
+
alt="Sand wool coat with broad lapels"
|
|
18
|
+
ratio="portrait"
|
|
19
|
+
fit="contain"
|
|
20
|
+
width={900}
|
|
21
|
+
height={1200}
|
|
22
|
+
fallback="Preview unavailable"
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## More examples
|
|
29
|
+
|
|
30
|
+
- [Crop and contain](https://kbui.kcb.pro/storybook/?path=/story/components-image--crop-and-contain): Compare detail crops with complete product images.
|
|
31
|
+
- [Ratios](https://kbui.kcb.pro/storybook/?path=/story/components-image--ratios): Square, wide, intrinsic and missing media.
|
|
32
|
+
- [Failure and recovery](https://kbui.kcb.pro/storybook/?path=/story/components-image--failure-and-recovery): Replace a failed source without shifting layout.
|
|
33
|
+
|
|
34
|
+
- [Editorial image library](https://kbui.kcb.pro/storybook/?path=/story/components-image--asset-library): Ten original portrait, object and scene illustrations with individual downloads.
|
|
35
|
+
|
|
36
|
+
## Reference
|
|
37
|
+
|
|
38
|
+
| Prop | Type | Default | Notes |
|
|
39
|
+
| --- | --- | --- | --- |
|
|
40
|
+
| `alt` | `string` | required | Accessible alternative; empty string hides decorative media |
|
|
41
|
+
| `src`, `srcSet`, `sizes` | native image attributes | unset | Responsive source selection; changing these resets request state |
|
|
42
|
+
| `ratio` | `ImageRatio` | `"landscape"` | `square` (1:1), `landscape` (4:3), `portrait` (3:4), `wide` (16:9), or `auto` |
|
|
43
|
+
| `width`, `height` | native image dimensions | unset | Forwarded to img; with `ratio="auto"`, reserve their ratio before loading |
|
|
44
|
+
| `fit` | `"cover"` \| `"contain"` | `"cover"` | Crop to fill or show entire image |
|
|
45
|
+
| `position` | CSS object position | browser center | Focal point, such as `"50% 25%"` |
|
|
46
|
+
| `fallback` | `ReactNode` | image outline icon | Non-interactive visual for loading, missing and failed media |
|
|
47
|
+
| `loading`, `fetchPriority` | native image attributes | browser defaults | Choose lazy/eager loading and priority per placement |
|
|
48
|
+
| `decoding` | native image attribute | `"async"` | Decode preference |
|
|
49
|
+
| `crossOrigin`, `referrerPolicy` | native image attributes | unset | Request policy |
|
|
50
|
+
| `onLoad`, `onError` | native image handlers | unset | Observe request outcome; called with native img events |
|
|
51
|
+
| `classNames` | keyed classes | unset | `root`, `image`, `fallback` |
|
|
52
|
+
| `ref` | `Ref<HTMLSpanElement>` | unset | Frame element; remaining span props and style apply here |
|
|
53
|
+
|
|
54
|
+
The frame exposes `data-state="empty|loading|loaded|error"`, `data-ratio`, and `data-fit`. The internal native image is hidden from assistive technology; the outer image role owns the alternative across all states. `aria-label`, `aria-labelledby`, and `aria-describedby` belong to the frame. An empty `alt` always hides the complete image.
|
|
55
|
+
|
|
56
|
+
`auto` uses positive width and height; without both, it falls back to the landscape ratio. The image remains within the reserved frame, including after failure. A caller `style.aspectRatio` overrides framing. `Image` fetches follow native browser behavior; the component adds no timeout, retry loop, cache, upload or URL policy. A new source starts a fresh request; to retry the same URL intentionally, change the component key.
|
|
57
|
+
|
|
58
|
+
Fallback content is visual-only and must contain no controls. Place a named replacement/retry `Button` and meaningful error text outside the frame. Use [media recipes](../../../../docs/guides/media-and-identity.md) for responsive sources, localized errors and CSS-only markup.
|
|
59
|
+
|
|
60
|
+
## Related components
|
|
61
|
+
|
|
62
|
+
Use [`Avatar`](Avatar.md) for fixed-size identity, [`Thumbnail`](Thumbnail.md) for captions and metadata, and [`Grid`](Grid.md) for responsive collections.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Inline
|
|
2
|
+
|
|
3
|
+
Use `Inline` for a row of content or controls that wraps when space runs out. Each control keeps its normal Tab stop; the row adds no toolbar role or keyboard handling. Native HTML props and the matching `ref` pass through.
|
|
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/layout-inline--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, Inline } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<Inline>
|
|
16
|
+
<Button>Save changes</Button>
|
|
17
|
+
<Button variant="secondary">Cancel</Button>
|
|
18
|
+
</Inline>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## More examples
|
|
24
|
+
|
|
25
|
+
- [Wrapping actions](https://kbui.kcb.pro/storybook/?path=/story/layout-inline--wrapping): Inspect source order as controls wrap.
|
|
26
|
+
- [A native list](https://kbui.kcb.pro/storybook/?path=/story/layout-inline--list): Retain list semantics inside a row.
|
|
27
|
+
- [Mixed content](https://kbui.kcb.pro/storybook/?path=/story/layout-inline--alignment): Compare alignment with different content sizes.
|
|
28
|
+
|
|
29
|
+
## Reference
|
|
30
|
+
|
|
31
|
+
| Prop | Values | Default |
|
|
32
|
+
| --------- | ---------------------------------------------- | -------- |
|
|
33
|
+
| `as` | `div` `ul` `ol` `nav` | `div` |
|
|
34
|
+
| `gap` | `none` `sm` (0.5rem) `md` (1rem) `lg` (1.5rem) | `md` |
|
|
35
|
+
| `align` | `start` `center` `end` `baseline` `stretch` | `center` |
|
|
36
|
+
| `justify` | `start` `center` `end` `between` | `start` |
|
|
37
|
+
|
|
38
|
+
Set `as` explicitly when using an element other than the default. Lists keep their markers and outer spacing; `gap` controls spacing between `<li>` children. Choose `Toolbar` when actions need arrow-key navigation. See [Layout composition](https://github.com/KhallilB/kbui/blob/main/docs/guides/layout.md).
|
|
39
|
+
|
|
40
|
+
## Related components
|
|
41
|
+
|
|
42
|
+
Use [`Toolbar`](Toolbar.md) when actions need coordinated arrow-key navigation. Use [`Stack`](Stack.md) for vertical flow and [`Grid`](Grid.md) when items need shared columns.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Input
|
|
2
|
+
|
|
3
|
+
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.
|
|
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-input--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Input } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return <Input label="Email" type="email" name="email" autoComplete="email" />;
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## More examples
|
|
19
|
+
|
|
20
|
+
- [Search and clear](https://kbui.kcb.pro/storybook/?path=/story/components-input--with-icons-and-actions): Keep the input stable while editing actions change.
|
|
21
|
+
- [Validation feedback](https://kbui.kcb.pro/storybook/?path=/story/components-input--with-error): Associate an error with the field.
|
|
22
|
+
- [A visually hidden label](https://kbui.kcb.pro/storybook/?path=/story/components-input--hidden-label): Retain the accessible name when hiding the visual label.
|
|
23
|
+
|
|
24
|
+
## Reference
|
|
25
|
+
|
|
26
|
+
| Prop | Type | Default | Notes |
|
|
27
|
+
| ----------------------------- | ---------------------- | -------- | ------------------------------------------------------------- |
|
|
28
|
+
| `startContent` / `endContent` | `ReactNode` | | Icons or actions at either end; give actions accessible names |
|
|
29
|
+
| `label` | `string` | required | Visible label and accessible name |
|
|
30
|
+
| `visuallyHidden` | `boolean` | | Hides the label visually but keeps it for screen readers |
|
|
31
|
+
| `description` | `string` | | Help text below the field |
|
|
32
|
+
| `error` | `string` | | Shows an error message and marks the field invalid |
|
|
33
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Field height. Replaces the native `size` attribute |
|
|
34
|
+
| `className` | `string` | | Applied to the wrapper, not the input element |
|
|
35
|
+
|
|
36
|
+
Other native `input` props, including `value` and `defaultValue`, pass through to the input. Base UI's `onValueChange` is also supported.
|
|
37
|
+
|
|
38
|
+
## Search composition
|
|
39
|
+
|
|
40
|
+
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.
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
import { useRef, useState } from "react";
|
|
44
|
+
import { Button, Input } from "@kb.ui/react";
|
|
45
|
+
|
|
46
|
+
export function SearchExample() {
|
|
47
|
+
const [query, setQuery] = useState("");
|
|
48
|
+
const control = useRef<HTMLInputElement>(null);
|
|
49
|
+
return (
|
|
50
|
+
<Input
|
|
51
|
+
ref={control}
|
|
52
|
+
label="Search components"
|
|
53
|
+
type="search"
|
|
54
|
+
name="q"
|
|
55
|
+
value={query}
|
|
56
|
+
onValueChange={setQuery}
|
|
57
|
+
endContent={
|
|
58
|
+
query ? (
|
|
59
|
+
<Button
|
|
60
|
+
type="button"
|
|
61
|
+
size="sm"
|
|
62
|
+
variant="ghost"
|
|
63
|
+
aria-label="Clear search"
|
|
64
|
+
onClick={() => {
|
|
65
|
+
setQuery("");
|
|
66
|
+
control.current?.focus();
|
|
67
|
+
}}
|
|
68
|
+
>
|
|
69
|
+
<span aria-hidden="true">×</span>
|
|
70
|
+
</Button>
|
|
71
|
+
) : undefined
|
|
72
|
+
}
|
|
73
|
+
/>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
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.
|
|
79
|
+
|
|
80
|
+
## Related components
|
|
81
|
+
|
|
82
|
+
Use [`Textarea`](Textarea.md) for multiline answers, [`NumberField`](NumberField.md) for numeric stepping, and [`Combobox`](Combobox.md) for a searchable choice from existing values.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Link
|
|
2
|
+
|
|
3
|
+
Native anchor for navigation, with persistent underline and visible keyboard focus.
|
|
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-link--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Link } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return <Link href="/projects">Browse projects</Link>;
|
|
15
|
+
}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## More examples
|
|
19
|
+
|
|
20
|
+
- [Navigation within prose](https://kbui.kcb.pro/storybook/?path=/story/components-link--in-text): Inspect link treatment inside surrounding text.
|
|
21
|
+
- [Router adapter](https://kbui.kcb.pro/storybook/?path=/story/components-link--with-router): Client-side navigation through `Link.Provider`.
|
|
22
|
+
|
|
23
|
+
## Reference
|
|
24
|
+
|
|
25
|
+
| Prop | Type | Default | Notes |
|
|
26
|
+
| ------------------------------------------- | ------------------- | -------- | -------------------------------- |
|
|
27
|
+
| `href` | `string` | required | Navigation destination |
|
|
28
|
+
| `target`, `rel`, `download`, `aria-current` | Native anchor props | unset | Passed through without rewriting |
|
|
29
|
+
| `className`, `ref` | Native anchor props | unset | Ref targets anchor |
|
|
30
|
+
|
|
31
|
+
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 is provided. Color, underline and focus must remain visible.
|
|
32
|
+
|
|
33
|
+
### Router links
|
|
34
|
+
|
|
35
|
+
kbui never imports a router. Wrap your app once in `Link.Provider` with a component that renders an anchor: it receives `href` plus native anchor props, and must pass them and `ref` through. `Link` then renders through it and keeps `kb-link`; nested providers override outer ones, and without a provider it renders a plain `<a>`. A React Router adapter:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { Link, type LinkProps } from "@kb.ui/react";
|
|
39
|
+
import { Link as RouterLink } from "react-router";
|
|
40
|
+
|
|
41
|
+
const AppLink = ({ href, ...props }: LinkProps) => <RouterLink to={href} {...props} />;
|
|
42
|
+
|
|
43
|
+
<Link.Provider component={AppLink}>
|
|
44
|
+
<App />
|
|
45
|
+
</Link.Provider>;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`useLinkComponent()` returns the current component for your own anchors.
|
|
49
|
+
|
|
50
|
+
## Related components
|
|
51
|
+
|
|
52
|
+
Use [`Button`](Button.md) for an action and [`Card`](Card.md) to group content around a destination.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Menu
|
|
2
|
+
|
|
3
|
+
Offer a short list of actions without leaving the current context. Use a `Select` when people are choosing a saved field value.
|
|
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-menu--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { Button, Menu } from "@kb.ui/react";
|
|
12
|
+
|
|
13
|
+
export function Example() {
|
|
14
|
+
return (
|
|
15
|
+
<Menu>
|
|
16
|
+
<Menu.Trigger render={<Button />}>Page actions</Menu.Trigger>
|
|
17
|
+
<Menu.Content>
|
|
18
|
+
<Menu.Item onClick={() => window.print()}>Print page</Menu.Item>
|
|
19
|
+
</Menu.Content>
|
|
20
|
+
</Menu>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## More examples
|
|
26
|
+
|
|
27
|
+
- [Keyboard interaction](https://kbui.kcb.pro/storybook/?path=/story/components-menu--default): Try the trigger, arrow keys, and dismissal.
|
|
28
|
+
- [A themed popup](https://kbui.kcb.pro/storybook/?path=/story/components-menu--nested-theme): Check that the popup uses its parent theme.
|
|
29
|
+
|
|
30
|
+
## Reference
|
|
31
|
+
|
|
32
|
+
| Part | Props and responsibility |
|
|
33
|
+
| ---------------- | ---------------------------------------------------------------------------------------- |
|
|
34
|
+
| `Menu` | Root; use open/`defaultOpen` and `onOpenChange` when your app controls visibility |
|
|
35
|
+
| `Menu.Trigger` | Named trigger; render a `Button` for shared styling |
|
|
36
|
+
| `Menu.Content` | Popup; side defaults to bottom, align to start; container chooses the themed portal host |
|
|
37
|
+
| `Menu.Item` | Action text and click handler; disabled prevents selection |
|
|
38
|
+
| `Menu.Separator` | Divides related groups without adding a focus stop |
|
|
39
|
+
|
|
40
|
+
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.
|
|
41
|
+
|
|
42
|
+
## Related components
|
|
43
|
+
|
|
44
|
+
Use [`Select`](Select.md) for a saved field value and [`Dialog`](Dialog.md) for a focused task with content or fields.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# MultiSelect
|
|
2
|
+
|
|
3
|
+
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. Choosing or deselecting an option keeps the popup open and preserves the filter. Escape, an outside click, or the toggle closes it.
|
|
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-multiselect--docs)
|
|
6
|
+
|
|
7
|
+
## Usage
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import "@kb.ui/react/styles.css";
|
|
11
|
+
import { useState } from "react";
|
|
12
|
+
import { MultiSelect } from "@kb.ui/react";
|
|
13
|
+
|
|
14
|
+
const scopes = [
|
|
15
|
+
{ value: "payments:read", label: "Payments read" },
|
|
16
|
+
{ value: "webhooks:manage", label: "Webhooks" },
|
|
17
|
+
{ value: "reporting:export", label: "Reporting export" },
|
|
18
|
+
];
|
|
19
|
+
|
|
20
|
+
export function ScopeMultiSelect() {
|
|
21
|
+
const [selected, setSelected] = useState<string[]>(["payments:read"]);
|
|
22
|
+
return (
|
|
23
|
+
<MultiSelect
|
|
24
|
+
label="API scopes"
|
|
25
|
+
options={scopes}
|
|
26
|
+
value={selected}
|
|
27
|
+
onValueChange={setSelected}
|
|
28
|
+
placeholder="Filter scopes..."
|
|
29
|
+
/>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## More examples
|
|
35
|
+
|
|
36
|
+
- [Several retained choices](https://kbui.kcb.pro/storybook/?path=/story/components-multiselect--many-selections): Inspect removable chips and their keyboard model.
|
|
37
|
+
- [No matching options](https://kbui.kcb.pro/storybook/?path=/story/components-multiselect--empty): Inspect the empty filtering state.
|
|
38
|
+
- [Validation feedback](https://kbui.kcb.pro/storybook/?path=/story/components-multiselect--invalid): Explain a selection that needs correction.
|
|
39
|
+
|
|
40
|
+
## Reference
|
|
41
|
+
|
|
42
|
+
| Prop | Type | Default | Notes |
|
|
43
|
+
| ----------------------- | --------------------------------------- | ------------------------- | ----------------------------------------------------- |
|
|
44
|
+
| `label` | `string` | required | Visible field label and accessible combobox name |
|
|
45
|
+
| `options` | `readonly MultiSelectOption[]` | required | Selectable options filtered by label |
|
|
46
|
+
| `value` | `readonly string[]` | required | Controlled array of selected option values |
|
|
47
|
+
| `onValueChange` | `(value: string[]) => void` | required | Called when selections are added, removed, or cleared |
|
|
48
|
+
| `placeholder` | `string` | unset | Input placeholder |
|
|
49
|
+
| `emptyMessage` | `ReactNode` | `"No matching options"` | Polite status text when no options match |
|
|
50
|
+
| `size` | `"sm" \| "md" \| "lg"` | `"md"` | Control height and text scale |
|
|
51
|
+
| `description` / `error` | `ReactNode` | unset | Associated help and invalid-state text |
|
|
52
|
+
| `disabled` / `readOnly` | `boolean` | `false` | Prevent edits and chip removal |
|
|
53
|
+
| `removeLabel` | `(option: MultiSelectOption) => string` | `"Remove {option.label}"` | Accessible name for each chip remove button |
|
|
54
|
+
| `container` | `Combobox.Portal.Props["container"]` | field root | Portal host; default retains nested theme |
|
|
55
|
+
| `classNames` | `ClassNames<MultiSelectSlot>` | unset | Extra classes for inner parts |
|
|
56
|
+
|
|
57
|
+
## Related components
|
|
58
|
+
|
|
59
|
+
Use [`Combobox`](Combobox.md) for one searchable choice and [`Checkbox`](Checkbox.md) for independent choices that should remain visible.
|