Marble UI
← Components

Model Picker

Preview: In composer

Model selector grouped by provider, with context size and capability badges.

Import

import { ModelPicker } from '@marbleui/ui'

Props

<ModelPicker>

PropTypeDefaultDescription
models *requiredModelOption[]—
onChange *required(id: string) => void—
value *requiredstring—
aria-labelstring—Accessible name of the picker (default "Model").
classNamestring—
placeholderstring'Choose model'Trigger text when nothing is selected.
variant'outline' | 'ghost''ghost'"ghost": borderless trigger for composers. "outline": field-like.

Accessibility

Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria Button · React Aria Header · React Aria ListBox · React Aria ListBoxItem · React Aria ListBoxSection · React Aria Popover · React Aria Select · React Aria SelectValue. Follow the primitive's docs for the full keyboard map.

Usage notes

Model menu for a chat composer, grouped by provider, with context size and capability badges. Pass it to PromptInput’s tools. For a general dropdown use Select.

const models: ModelOption[] = [
  { id: 'opus', name: 'Claude Opus 5.5', provider: 'Anthropic', description: 'Most capable, for complex work', context: '1M', badges: ['Reasoning'] },
  { id: 'local', name: 'Local 8B', provider: 'On device', description: 'Private, offline', context: '32K' },
]
<PromptInput onSubmit={send} tools={<ModelPicker models={models} value={model} onChange={setModel} />} />
  • Controlled only: value is the selected model’s id, and onChange receives the new one.
  • Groups follow the order in which each provider first appears. disabled: true keeps a model visible but unselectable.
  • variant="ghost" (default) is the borderless trigger for composers; "outline" looks like a field, for settings pages.
  • aria-label names the picker (default “Model”) and placeholder is the trigger text with nothing selected (default “Choose model”). Typing on the trigger jumps to matching model names.
Example source · show
import { useState } from 'react'
import { PromptInput } from '../prompt-input'
import { ModelPicker, type ModelOption } from './model-picker'

const models: ModelOption[] = [
  { id: 'opus', name: 'Claude Opus 5.5', provider: 'Anthropic', description: 'Most capable, for complex work', context: '1M', badges: ['Reasoning'] },
  { id: 'sonnet', name: 'Claude Sonnet 5.5', provider: 'Anthropic', description: 'Fast and smart for everyday tasks', context: '1M' },
  { id: 'haiku', name: 'Claude Haiku 5.5', provider: 'Anthropic', description: 'Fastest, for high volume', context: '200K' },
  { id: 'local', name: 'Local 8B', provider: 'On device', description: 'Private, offline', context: '32K', badges: ['Offline'] },
  { id: 'legacy', name: 'Legacy model', provider: 'On device', description: 'Retired', disabled: true },
]

function InComposer() {
  const [m, setM] = useState('sonnet')
  return <PromptInput className="w-[32rem]" onSubmit={() => {}} tools={<ModelPicker models={models} value={m} onChange={setM} />} />
}

function Outline() {
  const [m, setM] = useState('opus')
  return <ModelPicker models={models} value={m} onChange={setM} variant="outline" />
}

export const styles = { 'In composer': InComposer, Outline }

Source: packages/ui/src/model-picker/model-picker.tsx

Catalog

Category
ai-agents
Priority
Pro
Primitive
composed
React Aria
Select
Base UI
Select