Inspector Select

About this component

Inspector Select

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.

Usage

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} />

Playground

Turn the props on the right; the snippet under them is what you would write to get what you see.

Usage
import { InspectorSelect } from "@/components/beste/component/inspector-select";

<InspectorSelect
  label="Font"
  options={["Inter","Geist","Söhne","Untitled Sans"]}
  defaultValue="Inter"
/>

Keyboard and gestures

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 / SpaceOpen the menu.
Arrow keysMove through the options; the value follows as you go.
Type a letterJump to the next option starting with it.
EscapeClose and keep what was there before.

Props

Read from the component's own type, so this cannot drift from what it accepts.

PropTypeDefaultDescription
label*stringLabel rendered on the left, inside the row.
iconLucideIconOptional leading icon shown before the label.
options(string | InspectorSelectOption)[]Plain strings for simple lists, or objects for icons, swatches and groups.
valuestringControlled value. Pair it with `onValueChange`.
defaultValuestringInitial value in uncontrolled mode.
onValueChange(value: string) => void
onOpenChange(open: boolean) => voidFires when the menu opens or closes.
placeholderstring"Select"Shown in place of the value until something is selected.
emptyMessagestring"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.
disabledbooleanBlock 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.
namestringName of the underlying form control, so the row can take part in a form.
idstringId of the trigger, for an external `<label htmlFor>`.
classNamestring
aria-labelstringAccessible 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.

More Inspector components

View all Inspector

Inspector Color

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.

Inspector Input

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.

Inspector Switch

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.

Dark Mode

Inspector Segmented

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.

Inspector Variants

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.

Inspector Icon

Settings row that names the chosen icon and shows it on the right; pressing the row opens a searchable palette below it, width-matched to the row, with clearing offered at the foot of it. The icon set is passed in, so the row never bundles an icon library of its own.