Settings row that pairs a label with its current choice inside one pill, opening a width-matched dropdown below: option icons, colour swatches, descriptions and grouped sections, on top of the accessible shadcn select.
Adds the component and everything it depends on to your project.
npx shadcn add https://ui.beste.co/component/r-base/inspector-selectNew here? Read the installation guide.
The import and the props worth knowing about, in one place.
import { InspectorSelect } from "@/components/beste/component/inspector-select";
// Plain strings are enough for a simple list
<InspectorSelect label="Easing" options={["linear", "ease-in", "ease-out"]} defaultValue="ease-out" />
// Controlled, with a commit-shaped handler
<InspectorSelect
label="Blend mode"
value={blendMode}
onValueChange={setBlendMode}
onOpenChange={(open) => console.log("menu open:", open)}
options={[
{ value: "normal", label: "Normal" },
// Consecutive options sharing a group become one section, so the order
// you write is the order that renders.
{ value: "multiply", label: "Multiply", group: "Darken", description: "Keeps the darker pixels" },
{ value: "screen", label: "Screen", group: "Lighten" },
{ value: "hue", label: "Hue", group: "Component", disabled: true },
]}
/>
// Icons and colour swatches, per option
<InspectorSelect
label="Palette"
icon={Palette} // row icon, before the label
defaultValue="sunset"
options={[
{ value: "sunset", label: "Sunset", swatch: "#f97316" },
{ value: "ocean", label: "Ocean", swatch: "#0ea5e9" },
]}
/>
<InspectorSelect
label="Font"
tone="outline" // "muted" (default) | "outline" | "ghost"
size="sm" // "sm" | "default" | "lg"
menuWidth="auto" // "trigger" (default) matches the row width
placeholder="Inherit" // shown until something is selected
emptyMessage="No fonts found"
options={fonts}
/>
// Takes part in a form through the underlying select
<InspectorSelect label="Region" name="region" options={["EU", "US", "APAC"]} disabled={isSaving} />Turn the props on the right; the snippet under them is what you would write to get what you see.
import { InspectorSelect } from "@/components/beste/component/inspector-select";
<InspectorSelect
label="Font"
options={["Inter","Geist","Söhne","Untitled Sans"]}
defaultValue="Inter"
/>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.
| Enter / Space | Open the menu. |
|---|---|
| Arrow keys | Move through the options; the value follows as you go. |
| Type a letter | Jump to the next option starting with it. |
| Escape | Close and keep what was there before. |
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 | InspectorSelectOption)[] | — | Plain strings for simple lists, or objects for icons, swatches and groups. |
value | string | — | Controlled value. Pair it with `onValueChange`. |
defaultValue | string | — | Initial value in uncontrolled mode. |
onValueChange | (value: string) => void | — | |
onOpenChange | (open: boolean) => void | — | Fires when the menu opens or closes. |
placeholder | string | "Select" | Shown in place of the value until something is selected. |
emptyMessage | string | "No options" | Menu text when there is nothing to choose from. |
menuWidth | "trigger" | "auto" | "trigger" | Menu width: match the row, or size to the longest option. |
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. |
name | string | — | Name of the underlying form control, so the row can take part in a form. |
id | string | — | Id of the trigger, for an external `<label htmlFor>`. |
className | string | — | |
aria-label | string | — | Accessible name. Omit it and the row reads as "{label}, {value}", which is usually what you want — the visible label and the value are both announced. |
Settings row with a label on the left and a switch on the right, sharing the family's pill: the label takes the row's spare width, so a press almost anywhere toggles it.
Settings row that keeps the label, the colour value and a swatch on one pill; pressing the row opens the OKLCH colour picker below it, which is where the value is edited.
Settings row with a label on the left and a plain text field on the right, sharing the family's pill: the whole row is the label, so pressing anywhere puts the caret in the field.
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 holding a set of pills that are each on or off, so any number of them can be on at once: what inspector-segmented is for one choice out of several, this is for several choices at once, and what inspector-switch is for a single flag, this is for a handful that belong together.
The choice that has to be seen to be made: a template, a layout, a chart type. Each option is a picture, normally a rendered screenshot passed as a URL, or markup for the choices no photograph would show. The row is the trigger, the grid is width-matched to it, and the captions under the pictures can be dropped for a set whose pictures say everything.