Model Picker

Chooses an agent model.

Installation

pnpm dlx shadcn@latest add @paneui/model-picker

Usage

Examples

Searchable

Use when the list runs past a screen, such as a model router's catalogue.

Composer Picker

ACP

Feed ModePicker from an agent's SessionModeState, ModelPicker from a config option with category: "model" (grouped options map to provider), and EffortPicker from category: "thought_level".

With searchable focus stays in the search field: arrow keys move the highlight, Enter picks, Escape closes. Words match the label, value and group in any order. maxPerGroup caps each group until you search or press its “Show all” row; the current choice stays visible past the cap.

Descriptions

Model and effort rows show the name alone; a description you pass is kept and shows with showDescriptions. ModePicker and ComposerPicker show descriptions by default, since an access level needs its consequence spelled out.

Logos

Give each model its vendor's mark with <BrandIcon color="brand">. Marks the brand icon package leaves out, such as OpenAI and xAI, ship in @paneui/ui/lib/brand-marks with the same shape.

Testing

Every option carries its value as data-value, so tests can pick one without matching its label.

Tone

A mode with tone: "warning" (full access) or "destructive" colours the trigger while selected, so a risky setting is visible at a glance.

API Reference

ComposerPicker

options*
PickerOption[]
{ value, label, description?, icon?, group?, tone?, disabled? }.
value
string
Selected value.
onValueChange
(value: string) => void
Called on pick.
label*
string
Accessible name of the trigger.
icon
ReactNode
Trigger glyph when the option has none.
heading
string
Label above the options.
side= "top"
"top" | "bottom"
Menu side (top suits a composer at the bottom).
align= "start"
"start" | "center" | "end"
Menu alignment.
footer
ReactNode
Menu items under the options; with searchable, a plain button or link.
searchable= false
boolean
Search field at the top of the list.
searchPlaceholder= "Search"
string
Placeholder and accessible name of the search field.
emptyLabel= "No results"
ReactNode
Shown when nothing matches.
maxPerGroup
number
With searchable, options shown per group before “Show all”.
compact= false
boolean
Inside an AgentComposer toolbar narrower than 28rem (phones, tablets, split panes), show only the glyph and chevron; the label stays the accessible name. ModePicker and EffortPicker default to true.
showDescriptions= true
boolean
Show each option's description under its name. ModelPicker and EffortPicker default to false.
PropTypeDefaultDescription
options*PickerOption[]—{ value, label, description?, icon?, group?, tone?, disabled? }.
valuestring—Selected value.
onValueChange(value: string) => void—Called on pick.
label*string—Accessible name of the trigger.
iconReactNode—Trigger glyph when the option has none.
headingstring—Label above the options.
side"top" | "bottom""top"Menu side (top suits a composer at the bottom).
align"start" | "center" | "end""start"Menu alignment.
footerReactNode—Menu items under the options; with searchable, a plain button or link.
searchablebooleanfalseSearch field at the top of the list.
searchPlaceholderstring"Search"Placeholder and accessible name of the search field.
emptyLabelReactNode"No results"Shown when nothing matches.
maxPerGroupnumber—With searchable, options shown per group before “Show all”.
compactbooleanfalseInside an AgentComposer toolbar narrower than 28rem (phones, tablets, split panes), show only the glyph and chevron; the label stays the accessible name. ModePicker and EffortPicker default to true.
showDescriptionsbooleantrueShow each option's description under its name. ModelPicker and EffortPicker default to false.

ModelPicker

Preset grouped by provider.

models*
{ id, name, description?, provider?, icon? }[]
Models to offer.
PropTypeDefaultDescription
models*{ id, name, description?, provider?, icon? }[]—Models to offer.

EffortPicker

Preset with a bolt glyph.

levels= low / medium / high
{ value, label, description? }[]
Effort levels.
PropTypeDefaultDescription
levels{ value, label, description? }[]low / medium / highEffort levels.

ModePicker

Preset with a shield glyph.

modes*
{ id, name, description?, icon?, tone? }[]
Modes or access levels.
PropTypeDefaultDescription
modes*{ id, name, description?, icon?, tone? }[]—Modes or access levels.