Settings row for a list too long to read: pressing it opens a width-matched list with a search field, the keyboard walking the results while focus stays in the field. Options carry groups, descriptions, swatches and search keywords, and `multiple` turns the row into a counted multi-select.
Adds the component and everything it depends on to your project.
npx shadcn add https://ui.beste.co/component/r-base/inspector-comboboxNew here? Read the installation guide.
The import and the props worth knowing about, in one place.
import { InspectorCombobox } from "@/components/beste/component/inspector-combobox";
const pages = [
{ value: "home", label: "Home", group: "Pages" },
{ value: "pricing", label: "Pricing", group: "Pages" },
{ value: "docs", label: "Documentation", group: "Pages", keywords: ["help", "guide"] },
{ value: "cart", label: "Cart", group: "Shop" },
];
<InspectorCombobox label="Link to" options={pages} defaultValue="pricing" />
// Controlled. The argument is a string here and an array under `multiple`, so
// narrow it at the call site, which is what knows which it asked for.
<InspectorCombobox
label="Link to"
options={pages}
value={page}
onValueChange={(next) => setPage(next as string)}
onOpenChange={(open) => console.log("list open:", open)}
searchable // on by default past eight options
searchPlaceholder="Find a page"
placeholder="Choose a page" // shown while nothing is selected
emptyMessage="No page matches"
clearable // adds a "Clear Link to" button at the foot
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
/>
// Several at once: the row counts them, and the list stays open between presses
<InspectorCombobox
label="Categories"
multiple
max={3}
options={["Editorial", "Commerce", "Marketing", "Docs"]}
value={categories}
onValueChange={(next) => setCategories(next as string[])}
/>
// Options can carry a mark and a second line
<InspectorCombobox
label="Theme"
options={[
{ value: "sand", label: "Sand", swatch: "#d6cbb8", description: "Warm neutral" },
{ value: "slate", label: "Slate", swatch: "#64748b", description: "Cool neutral" },
]}
/>Turn the props on the right; the snippet under them is what you would write to get what you see.
import { InspectorCombobox } from "@/components/beste/component/inspector-combobox";
<InspectorCombobox
label="Link to"
className="w-72"
defaultValue="pricing"
options={[{"value":"home","label":"Home","group":"Pages"},{"value":"pricing","label":"Pricing","group":"Pages"},{"value":"about","label":"About","group":"Pages"},{"value":"contact","label":"Contact","group":"Pages"},{"value":"blog","label":"Blog index","group":"Pages"},{"value":"changelog","label":"Changelog","group":"Pages"},{"value":"docs","label":"Documentation","group":"Pages","keywords":["help","guide"]},{"value":"cart","label":"Cart","group":"Shop"},{"value":"checkout","label":"Checkout","group":"Shop"},{"value":"account","label":"Account","group":"Shop"}]}
/>Every one of these is in the component already. They are listed because a props table cannot mention a gesture, so nothing else on this page can tell you they exist.
| Down / Up | Move through the results without leaving the search field |
|---|---|
| Home / End | Jump to the first or last result |
| Enter | Choose the active result |
| Escape | Close the list, leaving the value alone |
| Typing | Filters on the label, the value, the description and any keywords |
Read from the component's own type, so this cannot drift from what it accepts.
| Prop | Type | Default | Description |
|---|---|---|---|
label* | string | — | Label rendered on the left, inside the row. |
icon | LucideIcon | — | Optional leading icon shown before the label. |
options | (string | InspectorComboboxOption)[] | — | The options on offer. |
value | string | string[] | — | Controlled selection: a string, or an array of them with `multiple`. Pair it with `onValueChange`. |
defaultValue | string | string[] | — | Initial selection in uncontrolled mode. |
onValueChange | (value: ComboboxValue) => void | — | Fires on every selection. The argument is a string, or an array of them when `multiple` is set — narrow it at the call site, which knows which it asked for. |
onOpenChange | (open: boolean) => void | — | Fires when the list opens or closes. |
multiple | boolean | — | Choose several. The row then counts them and the list keeps itself open. |
max | number | — | Ceiling on how many may be chosen at once, with `multiple`. |
searchable | boolean | — | Show the search field. Defaults to on once there are more than eight options, which is the point at which reading the list stops being faster than typing. |
searchPlaceholder | string | — | Ghost text for the search field. |
placeholder | string | — | Shown in the row while nothing is selected. |
emptyMessage | string | — | Message shown when nothing matches the search. |
clearable | boolean | — | Offer a clear button at the foot of the list once something is selected. |
disabled | boolean | — | Block interaction and dim the row. |
tone | "muted" | "outline" | "ghost" | "muted" | Surface treatment: filled (default), hairline outline, or bare until hover. |
size | "sm" | "default" | "lg" | "default" | Row height preset. |
className | string | — | |
aria-label | string | — | Accessible name. Falls back to `label`. |
Settings row whose choices sit side by side on the right, with a marker that slides between them: the readable alternative to a switch when the two states deserve names, and the compact one to a select at three or four options.
Settings row for the four corners of a box: the row carries a border-radius shorthand summary and a glyph rounded to match, and opens a square where each field sits on the corner it rounds.
Settings row for the four edges of a box: the row carries a CSS-shorthand summary, and opens a cross where each field sits on the edge it sets, tied together or not.
Width and height on one row, with the lock between them: while it is closed, editing one scales the other by the ratio the pair had when the lock closed. Both fields are as wide as the largest number they can hold, so typing never shifts the row.
Settings block for a list of short strings: tags are typed one after another and wrap under the label, a comma or a paste splits several at once, and Backspace on an empty field reaches back into the list. Collapsible, so a long list folds down to the height of a row with the count still on it.