Inspector Toggles

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.

Borders

Installation

Adds the component and everything it depends on to your project.

npx shadcn add https://ui.beste.co/component/r-base/inspector-toggles

New here? Read the installation guide.

Usage

The import and the props worth knowing about, in one place.

import { InspectorToggles } from "@/components/beste/component/inspector-toggles";

// Which sides get a border. Four pills only fit as icons.
<InspectorToggles
  label="Borders"
  options={[
    { value: "left", icon: PanelLeftIcon },
    { value: "right", icon: PanelRightIcon },
    { value: "top", icon: PanelTopIcon },
    { value: "bottom", icon: PanelBottomIcon },
  ]}
  value={sides}
  onValueChange={setSides}
/>

// Plain strings when the value is the text
<InspectorToggles label="Weekend" options={["Sat", "Sun"]} defaultValue={["Sat"]} />

// A floor and a ceiling on how many may be on
<InspectorToggles
  label="Corners"
  min={1}                 // the last one on stops answering instead of vanishing
  max={2}                 // the ones still off dim once the ceiling is reached
  options={["TL", "TR", "BR", "BL"]}
  value={corners}
  onValueChange={setCorners}
/>

<InspectorToggles
  label="Effects"
  icon={SparklesIcon}     // optional leading icon
  tone="outline"          // "muted" (default) | "outline" | "ghost"
  size="sm"               // "sm" | "default" | "lg"
  options={[
    { value: "blur", label: "Blur" },
    { value: "grain", label: "Grain" },
    { value: "glow", label: "Glow", disabled: true },
  ]}
  value={effects}
  onValueChange={setEffects}
/>

// The pills are checkboxes sharing one name, so the row submits with a form
<InspectorToggles label="Days" name="days" options={["Mon", "Tue", "Wed"]} />

// Values come back in the order the options declare them, not the order pressed
<InspectorToggles
  label="Sides"
  options={["left", "right", "top", "bottom"]}
  onValueChange={(value) => console.log(value)}  // ["left", "top"], never ["top", "left"]
/>

Playground

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

Weekend
Usage
import { InspectorToggles } from "@/components/beste/component/inspector-toggles";

<InspectorToggles
  label="Weekend"
  options={["Mon","Tue","Wed","Thu"]}
  defaultValue={["Mon","Wed"]}
/>

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.

TabMove between the pills — they are separate checkboxes, not one control with an inner cursor.
SpaceTurn the focused pill on or off.

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 | InspectorTogglesOption)[]The toggles. Plain strings are enough when the value is the text. Past three or four with words, give them icons instead: the row is one line tall and a set of pills is only useful while it fits on it.
valuestring[]Controlled value. Pair it with `onValueChange`.
defaultValuestring[]Initial value in uncontrolled mode.
onValueChange(value: string[]) => voidFires on every toggle, with the values in the order `options` gives them — never in the order they were pressed, so the array can be compared and stored as-is.
minnumber0Fewest toggles that may be on. The last one on stops answering rather than disappearing, since a pill that vanishes at the boundary is worse than one that plainly refuses.
maxnumberMost toggles that may be on. Once reached, the ones still off dim, which is the only way a reader can tell why pressing them does nothing.
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 shared by the underlying checkboxes, so the row can take part in a form.
classNamestring
aria-labelstringAccessible name for the group. Falls back to `label`.

More Inspector components

View all Inspector
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 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.

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.

Inspector Tabs

The strip that splits a settings panel into two or three questions instead of one long scroll. It is the strip and nothing else: what the tabs switch between stays in the panel's own markup, beside the state that decides it. The pill slides between equal columns, arrow keys both move and select, and a tab can carry a count of what has changed under it.

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 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.