Design system
Docs
Desktop

Settings controls

chrome/settings-controls.tsx: the row, select, switch, and stepper every Settings page is built from

Import
import {
  SettingsRow,
  SettingsSelect,
  SettingsStepper,
  SettingsSwitch,
} from "../chrome/settings-controls.tsx";

File: packages/desktop/src/renderer/src/chrome/settings-controls.tsx. Styles come from theme/settings-patterns.stylex.ts (settingsPatterns: section, sectionHeader, sectionTitle, sectionDescription, group, row, rowCopy, rowTitle, rowDescription, rowControl, …). Every Settings section is section › sectionHeader › group › SettingsRow*.

SettingsRow

Title and description on the left, one control on the right, optional detail below.

PropTypeDefaultDescription
titlestringRequired.
descriptionstringRequired. One sentence; can change with state ("Connect a provider below to choose one").
variant"standard" | "slider""standard"Slider rows are taller.
controlWidth"standard" | "wide""standard"Wide for model selects.
detailReactNodeA block under the row (a slider's readout).
childrenReactNodeThe control.

The row does not create a <label>; each control carries its own aria-label.

SettingsSelect<T extends string>

Over @nyte-ai/ui/select: `Select.Root › Trigger(aria-label) › Value

  • Icon › Portal › Positioner › Popup › List › Item › ItemText + ItemIndicator`.
PropTypeDefaultDescription
labelstringRequired. aria-label on the trigger.
valueTRequired, controlled.
optionsreadonly SettingsSelectOption<T>[]{ value, label, fontFamily? }.
disabledbooleanfalse
width"standard" | "wide""standard"
onValueChange(value: T) => voidRequired.

SettingsSelectOption.fontFamily exists because "installed family names cannot be compiled into StyleX"; the font-family select sets it inline per item. Collision avoidance is { side: "flip", align: "shift", fallbackAxisSide: "none" }.

Keyboard is Base UI Select's: Arrow keys move, typeahead, Enter/Space select, Escape closes, and the popup aligns the selected item over the trigger.

SettingsSwitch

Over @nyte-ai/ui/switch.

PropTypeDescription
labelstringRequired. aria-label.
checkedbooleanRequired.
disabledboolean
titlestringNative tooltip explaining why it is disabled (the reduce-transparency switch when the OS already reduces it).
onCheckedChange(checked: boolean) => voidRequired.

role="switch", aria-checked; Space toggles.

SettingsStepper

Over @nyte-ai/ui/number-field, with decrement and increment IconButtons around the value.

PropTypeDescription
labelstringRequired.
valuenumberRequired.
minimumnumberRequired.
maximumnumberRequired.
onValueChange(value: number) => voidRequired.

Arrow Up/Down step, Home/End jump to min/max, the buttons repeat on hold.

Where they appear

PageControls
GeneralSettingsSelect (window restoration)
AppearanceSettingsSelect (theme, fonts), SettingsSwitch ×4, SettingsStepper ×2, Slider rows
ModelsSettingsSelect (default model, thinking, default subagent model), SettingsSwitch per provider and model
Usagenone; toggle group and drag-sortable cards
Accountsnone; ConnectionList rows

See Surfaces › Settings.