---
title: Model Selector
description: A dropdown for selecting an AI model with radio groups, sub-menus, and custom items
---
import ModelSelectorDefault from "@/components/nexus-ui/examples/model-selector/default";
import ModelSelectorBasic from "@/components/nexus-ui/examples/model-selector/basic";
import ModelSelectorWithSub from "@/components/nexus-ui/examples/model-selector/with-sub";
import ModelSelectorWithItems from "@/components/nexus-ui/examples/model-selector/with-items";
import ModelSelectorWithCheckbox from "@/components/nexus-ui/examples/model-selector/with-checkbox";
import ModelSelectorTriggerVariants from "@/components/nexus-ui/examples/model-selector/trigger-variants";
import ModelSelectorWithPromptInput from "@/components/nexus-ui/examples/model-selector/with-prompt-input";
import ModelSelectorCustomTrigger from "@/components/nexus-ui/examples/model-selector/custom-trigger";
import ModelSelectorWithSearch from "@/components/nexus-ui/examples/model-selector/with-search";
A composable dropdown for selecting AI models. Built on [Radix UI Dropdown Menu](https://www.radix-ui.com/primitives/docs/components/dropdown-menu),
it supports radio groups for single selection, sub-menus for nested options, plain items for toggles or actions, and separators for grouping.
The trigger displays the selected model's icon and title when you pass an `items` array.
## Installation
```bash
npx shadcn@latest add @nexus-ui/model-selector
```
```bash
pnpm dlx shadcn@latest add @nexus-ui/model-selector
```
```bash
yarn dlx shadcn@latest add @nexus-ui/model-selector
```
```bash
bunx shadcn@latest add @nexus-ui/model-selector
```
Copy and paste the following code into your project.
Update the import paths to match your project setup.
## Usage
```tsx keepBackground
import {
ModelSelector,
ModelSelectorTrigger,
ModelSelectorContent,
ModelSelectorGroup,
ModelSelectorLabel,
ModelSelectorRadioGroup,
ModelSelectorRadioItem,
} from "@/components/nexus-ui/model-selector";
```
```tsx keepBackground noCollapse
Select model
{models.map((m) => (
))}
```
## Examples
### Basic
A minimal model selector with radio items. No icons, descriptions, or labels.
### Trigger Variants
The trigger supports three variants: `filled` (default), `outline`, and `ghost`. Use `outline` or `ghost` when placing
the model selector inside a [Prompt Input](/docs/components/prompt-input) or other dense UI.
### Custom Trigger
Pass custom `children` to `ModelSelectorTrigger` to override the default icon-and-title layout.
You control the content entirely—use your own copy, icons, and layout.
### With Sub-menus
Use `ModelSelectorSub`, `ModelSelectorSubTrigger`, `ModelSelectorPortal`, and `ModelSelectorSubContent` for nested
options like provider-specific model groups.
### With Checkbox
Use `ModelSelectorCheckboxItem` alone for multi-select. Each item is a checkbox—toggle models on or off. Use a custom
trigger to show the selection (e.g. "Select models", "GPT-4", or "3 models").
### With Prompt Input
Place the model selector in a `PromptInputActionGroup` alongside attach, image, mic, and send buttons.
### With Search
Place `ModelSelectorSearch` first in `ModelSelectorContent`; the root owns the query and clears it when the menu closes (`onOpenChange` still runs if you pass it). Radio items filter on `value`, `title`, and `description`; checkbox items on `title` and `description` only; plain `ModelSelectorItem` rows are not filtered. Optional search `onChange` runs after internal updates. `ModelSelectorEmpty` needs root `items` to show no-match copy (default: No models found).
### With Items and Separators
Use `ModelSelectorItem` for non-selection actions (e.g. extended thinking toggle) and `ModelSelectorSeparator`
to divide sections.
## Vercel AI SDK Integration
Use the Model Selector with the [Vercel AI SDK](https://sdk.vercel.ai) to let users pick which model powers the chat. Pass the selected model to your API via `prepareSendMessagesRequest`.
Install the AI SDK
```bash
npm install ai @ai-sdk/react @ai-sdk/openai
```
Create your chat API route
Create a route that reads `model` from the request body:
```ts title="app/api/chat/route.ts"
import { convertToModelMessages, streamText, UIMessage } from "ai";
import { openai } from "@ai-sdk/openai";
export async function POST(req: Request) {
const { messages, model = "gpt-4o-mini" }: { messages: UIMessage[]; model?: string } =
await req.json();
const result = streamText({
model: openai(model),
system: "You are a helpful assistant.",
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}
```
Wire Model Selector + Prompt Input to `useChat`
```tsx
"use client";
import { useState } from "react";
import { useChat } from "@ai-sdk/react";
import { DefaultChatTransport } from "ai";
import { Button } from "@/components/ui/button";
import PromptInput, {
PromptInputActions,
PromptInputAction,
PromptInputActionGroup,
PromptInputTextarea,
} from "@/components/nexus-ui/prompt-input";
import {
ModelSelector,
ModelSelectorContent,
ModelSelectorGroup,
ModelSelectorLabel,
ModelSelectorRadioGroup,
ModelSelectorRadioItem,
ModelSelectorTrigger,
} from "@/components/nexus-ui/model-selector";
import ChatgptIcon from "@/components/svgs/chatgpt";
import {
ArrowUp02Icon,
PlusSignIcon,
SquareIcon,
} from "@hugeicons/core-free-icons";
import { HugeiconsIcon } from "@hugeicons/react";
const models = [
{ value: "gpt-4", icon: ChatgptIcon, title: "GPT-4", description: "Most capable" },
{ value: "gpt-4o-mini", icon: ChatgptIcon, title: "GPT-4o Mini", description: "Fast" },
{ value: "gpt-4o", icon: ChatgptIcon, title: "GPT-4o", description: "Multimodal" },
];
export default function ChatWithModelSelector() {
const [model, setModel] = useState("gpt-4o-mini");
const { sendMessage, status } = useChat({
transport: new DefaultChatTransport({
api: "/api/chat",
prepareSendMessagesRequest: ({ body }) => ({
body: { ...body, model },
}),
}),
});
const [input, setInput] = useState("");
const isLoading = status !== "ready";
const handleSubmit = (value?: string) => {
const text = (value ?? input).trim();
if (text) {
sendMessage({ text });
setInput("");
}
};
return (
);
}
```
For multi-provider support (OpenAI, Anthropic, etc.), add `@ai-sdk/anthropic` and similar, then map the model value to the correct provider in your API route.
## API Reference
The Model Selector primitives extend [Radix UI Dropdown Menu](https://www.radix-ui.com/primitives/docs/components/dropdown-menu).
For props like `open`, `onOpenChange`, `modal`, `dir`, etc., refer to the Radix docs. Below are the props specific to
the Model Selector.
### ModelSelector
Root component. Provides `value`, `onValueChange`, and `items` to children via context.
void",
description: "Called when the selection changes.",
},
onOpenChange: {
type: "(open: boolean) => void",
description:
"Forwarded from the Radix menu root. The root also clears the internal search query when the menu closes.",
},
items: {
type: "Array<{ value: string; icon?: React.ComponentType<{ className?: string }>; title: string; description?: string }>",
description:
"Optional. Used by ModelSelectorTrigger to display the selected model's icon and title. Omit for custom trigger content.",
},
}}
/>
### ModelSelectorTrigger
The button that opens the dropdown. Shows selected model (icon + title) when `items` is provided, or custom `children`.
Supports `asChild` to merge into a child element (e.g. Button).
### ModelSelectorSearch
A search input bound to the root filter query; radio and checkbox items hide when they do not match. Place at the top of `ModelSelectorContent`. Accepts standard `` props.
### ModelSelectorEmpty
Shown when the query is non-empty, `items` is set on the root, and none of those entries match the filter. Otherwise hidden. Default copy: No models found. Accepts standard `
` props.
### ModelSelectorItem
A plain menu item (no selection state). Use for toggles, links, or actions.
### ModelSelectorItemTitle
A paragraph for the item title. Used internally by CheckboxItem and RadioItem when `title` is provided. Accepts standard `p` element props.
### ModelSelectorItemDescription
A paragraph for the item description. Used internally by CheckboxItem and RadioItem when `description` is provided. Accepts standard `p` element props.
### ModelSelectorItemIcon
A span wrapper for the item icon. Used internally by CheckboxItem and RadioItem when `icon` is provided. Accepts standard `span` element props.
### ModelSelectorItemIndicator
A span that wraps selection indicators. Renders children inside Radix `ItemIndicator` by default. Use `wrapWithItemIndicator={false}` for always-visible content (e.g. LockIcon when disabled).
### ModelSelectorCheckboxItem
A checkbox-style item for multi-select. Shows a check indicator when `checked` is true, or a lock icon when `disabled`.
",
description: "Optional icon component for the item.",
},
indicator: {
type: "React.ReactNode",
default: "CheckIcon",
description:
"Custom indicator to show when selected. Renders inside ItemIndicator.",
},
title: {
type: "string",
description: "Optional title. Override with children for full control.",
},
description: {
type: "string",
description: "Optional description shown below the title.",
},
}}
/>
### ModelSelectorRadioItem
A radio-style item for single selection. Shows a check when selected, or a lock icon when `disabled`.
",
description: "Optional icon component for the item.",
},
indicator: {
type: "React.ReactNode",
default: "CheckIcon",
description:
"Custom indicator to show when selected. Renders inside ItemIndicator.",
},
title: {
type: "string",
description: "Optional title. Override with children for full control.",
},
description: {
type: "string",
description: "Optional description shown below the title.",
},
}}
/>
### Other primitives
`ModelSelectorContent`, `ModelSelectorPortal`, `ModelSelectorGroup`, `ModelSelectorLabel`, `ModelSelectorRadioGroup`,
`ModelSelectorSeparator`, `ModelSelectorSub`, `ModelSelectorSubTrigger`, and `ModelSelectorSubContent` accept the
same props as their Radix Dropdown Menu counterparts. See the
[Radix Dropdown Menu documentation](https://www.radix-ui.com/primitives/docs/components/dropdown-menu) for details.
`ModelSelectorItemTitle`, `ModelSelectorItemDescription`, `ModelSelectorItemIcon`, and `ModelSelectorItemIndicator`
are low-level building blocks used by CheckboxItem and RadioItem. Use them when composing custom item content with `children`.