ModelSelector

Model picker with unified overlay positioning and runtime integration.

A select component that lets users switch between AI models. Uses item-aligned positioning so the selected model overlays the trigger for a unified look. Integrates with assistant-ui's ModelContext system to automatically propagate the selected model to your backend.

Outline (default)
Ghost
Muted

Getting Started

Add model-selector

npx shadcn@latest add https://r.assistant-ui.com/model-selector.json

Use in your application

Place the ModelSelector inside your thread component, typically in the composer area:

/components/assistant-ui/thread.tsx
import { ModelSelector } from "@/components/assistant-ui/model-selector";

const ComposerAction: FC = () => {
  return (
    <div className="flex items-center gap-1">
      <ModelSelector
        models={[
          { id: "gpt-5-nano", name: "GPT-5 Nano", description: "Fast and efficient" },
          { id: "gpt-5-mini", name: "GPT-5 Mini", description: "Balanced performance" },
          { id: "gpt-5", name: "GPT-5", description: "Most capable" },
        ]}
        defaultValue="gpt-5-mini"
        size="sm"
      />
    </div>
  );
};

Read the model in your API route

The selected model name is sent as config.modelName in the request body:

app/api/chat/route.ts
export async function POST(req: Request) {
  const { messages, config } = await req.json();

  const result = streamText({
    model: openai(config?.modelName ?? "gpt-4o"),
    messages: convertToModelMessages(messages),
  });

  return result.toUIMessageStreamResponse();
}

Variants

Use the variant prop to change the trigger's visual style.

<ModelSelector variant="outline" /> // Border (default)
<ModelSelector variant="ghost" />   // No background
<ModelSelector variant="muted" />   // Solid background
VariantDescription
outlineBorder with transparent background (default)
ghostNo background, subtle hover
mutedSolid secondary background

Sizes

Use the size prop to control the trigger dimensions.

<ModelSelector size="sm" />      // Compact (h-8, text-xs)
<ModelSelector size="default" /> // Standard (h-9)
<ModelSelector size="lg" />      // Large (h-10)

Model Options

Each model in the models array supports:

const models = [
  {
    id: "gpt-5",           // Sent to backend as config.modelName
    name: "GPT-5",         // Display name in trigger and items
    description: "Most capable", // Optional subtitle in items only
    icon: <SparklesIcon />,      // Optional icon (any ReactNode)
  },
];

Runtime Integration

The default ModelSelector export automatically registers the selected model with assistant-ui's ModelContext system. When a user selects a model:

  1. The component calls api.modelContext().register() with config.modelName
  2. The AssistantChatTransport includes config in the request body
  3. Your API route reads config.modelName to determine which model to use

This works out of the box with @assistant-ui/react-ai-sdk.

API Reference

Composable API

For custom layouts, use the sub-components directly with ModelSelector.Root:

import {
  ModelSelectorRoot,
  ModelSelectorTrigger,
  ModelSelectorContent,
  ModelSelectorItem,
} from "@/components/assistant-ui/model-selector";

<ModelSelectorRoot models={models} value={modelId} onValueChange={setModelId}>
  <ModelSelectorTrigger variant="outline" />
  <ModelSelectorContent />
</ModelSelectorRoot>
ComponentDescription
ModelSelectorDefault export with runtime integration
ModelSelector.RootPresentational root (no runtime, controlled state)
ModelSelector.TriggerCVA-styled trigger showing current model
ModelSelector.ContentSelect content with model items
ModelSelector.ItemIndividual model option with icon, name, description

ModelSelector

ModelSelectorProps
modelsrequired: ModelOption[]

Array of available models to display.

defaultValue?: string

Initial model ID for uncontrolled usage.

value?: string

Controlled selected model ID.

onValueChange?: (value: string) => void

Callback when selected model changes.

variant: "outline" | "ghost" | "muted"= "outline"

Visual style of the trigger button.

size: "sm" | "default" | "lg"= "default"

Size of the trigger button.

contentClassName?: string

Additional class name for the dropdown content.

ModelOption

ModelOption
idrequired: string

Unique identifier sent to the backend as modelName.

namerequired: string

Display name shown in trigger and dropdown.

description?: string

Optional subtitle shown below the model name.

icon?: React.ReactNode

Optional icon displayed before the model name.