suiss/ui
  • Docs
  • Components
  • Patterns
  • Interactions
  • Charts
  • Blocks
  • AI
GitHubCreate
DocsComponentsPatternsInteractionsChartsBlocksAICreate
AI21
  • Overview
Conversation
  • Chat
  • Message
  • Prompt Input
  • Suggestion
  • Model Selector
  • Context
  • Checkpoint
  • Inline Citation
Agent steps
  • Chain of Thought
  • Reasoning
  • Tool
  • Confirmation
  • Task
  • Plan
  • Queue
  • Subagent
  • Sources
Output
  • Terminal
  • Stack Trace
  • Test Results
  • File Tree

suiss/ui · AI

Model Selector

Two menus in the prompt input: one picks the model the agent runs, the other picks how much effort it spends.

"use client"

import { ArrowUpIcon, CaretDownIcon, PlusIcon } from "@phosphor-icons/react"
import * as React from "react"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuLabel,
  DropdownMenuRadioGroup,
  DropdownMenuRadioItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import {
  InputGroup,

The model selector is two Dropdown Menu radio groups in the Prompt Input. One picks the model, grouped by provider, and the other picks the reasoning effort. Each trigger shows the current choice.

Installation

The model selector is built with Dropdown Menu and Input Group.

$ pnpm dlx shadcn@latest add @esuiss/dropdown-menu @esuiss/input-group

Or use the suiss/ui CLI:

$ pnpm dlx @esuiss/ui@latest add dropdown-menu input-group

Usage

<DropdownMenu>
  <DropdownMenuTrigger render={<InputGroupButton size="sm" variant="outline" />}>
    {modelName}
    <ChevronDownIcon />
  </DropdownMenuTrigger>
  <DropdownMenuContent align="start">
    <DropdownMenuRadioGroup value={model} onValueChange={setModel}>
      <DropdownMenuGroup>
        <DropdownMenuLabel>Anthropic</DropdownMenuLabel>
        <DropdownMenuRadioItem value="claude-opus-5-5" closeOnClick>
          Claude Opus 5.5
        </DropdownMenuRadioItem>
      </DropdownMenuGroup>
    </DropdownMenuRadioGroup>
  </DropdownMenuContent>
</DropdownMenu>

Set closeOnClick on each radio item so the menu closes once a model is picked.

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <InputGroupButton size="sm" variant="outline">
      {modelName}
      <ChevronDownIcon />
    </InputGroupButton>
  </DropdownMenuTrigger>
  <DropdownMenuContent align="start">
    <DropdownMenuRadioGroup value={model} onValueChange={setModel}>
      <DropdownMenuGroup>
        <DropdownMenuLabel>Anthropic</DropdownMenuLabel>
        <DropdownMenuRadioItem value="claude-opus-5-5" closeOnClick>
          Claude Opus 5.5
        </DropdownMenuRadioItem>
      </DropdownMenuGroup>
    </DropdownMenuRadioGroup>
  </DropdownMenuContent>
</DropdownMenu>

Set closeOnClick on each radio item so the menu closes once a model is picked.

<DropdownMenu>
  <InputGroupButton size="sm" variant="outline">
    {modelName}
    <ChevronDownIcon />
  </InputGroupButton>
  <DropdownMenuContent>
    <DropdownMenuRadioGroup value={model} onChange={setModel}>
      <DropdownMenuLabel>Anthropic</DropdownMenuLabel>
      <DropdownMenuRadioItem value="claude-opus-5-5" shouldCloseOnSelect>
        Claude Opus 5.5
      </DropdownMenuRadioItem>
    </DropdownMenuRadioGroup>
  </DropdownMenuContent>
</DropdownMenu>

Use one radio group per provider, and set shouldCloseOnSelect on each radio item so the menu closes once a model is picked.

Give each trigger an aria-label that includes the current choice, such as "Model: Claude Opus 5.5", so the value is announced along with what the menu changes.

AI SDK

Send the model and the effort with the message. Map them to a model and provider options in the route.

sendMessage({ text }, { body: { model, effort } })
app/api/chat/route.ts
import { anthropic } from "@ai-sdk/anthropic"
import { openai } from "@ai-sdk/openai"
import { convertToModelMessages, streamText, type UIMessage } from "ai"

const models = {
  "claude-opus-5-5": anthropic("claude-opus-5-5"),
  "claude-sonnet-5-5": anthropic("claude-sonnet-5-5"),
  "gpt-5": openai("gpt-5"),
  "gpt-5-mini": openai("gpt-5-mini"),
}

export async function POST(req: Request) {
  const { messages, model, effort } = (await req.json()) as {
    messages: UIMessage[]
    model: keyof typeof models
    effort: "low" | "medium" | "high"
  }

  const result = streamText({
    model: models[model] ?? models["claude-opus-5-5"],
    messages: await convertToModelMessages(messages),
    providerOptions: {
      anthropic: { effort },
      openai: { reasoningEffort: effort },
    },
  })

  return result.toUIMessageStreamResponse()
}

Each provider reads its own key in providerOptions and ignores the rest.

API Reference

See Dropdown Menu and Input Group.

import { CaretDownIcon } from "phosphor-react-native"
import * as React from "react"
import { View } from "react-native"
import { Button } from "@/components/ui/button"
import { DropdownMenu, DropdownMenuContent, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"
import { Icon } from "@/components/ui/icon"
import { Text } from "@/components/ui/text"

const providers = [
  { name: "Anthropic", models: ["Claude Opus 5.5", "Claude Sonnet 5.5"] },
  { name: "OpenAI", models: ["GPT-5", "GPT-5 mini"] },
]

function ModelSelector() {
  const [model, setModel] = React.useState("Claude Opus 5.5")
  return (
import EsuissUI
import PhosphorSwift
import SwiftUI

struct ModelSelectorExample: View {
  @State private var model = "Claude Opus 5.5"

  var body: some View {
    DropdownMenu {
      DropdownMenuLabel("Anthropic")
      DropdownMenuRadioGroup(selection: $model) {
        DropdownMenuRadioItem("Claude Opus 5.5", value: "Claude Opus 5.5")
        DropdownMenuRadioItem("Claude Sonnet 5.5", value: "Claude Sonnet 5.5")
      }
      DropdownMenuSeparator()
      DropdownMenuLabel("OpenAI")
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.width
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.esuiss.ui.components.Button
import com.esuiss.ui.components.ButtonSize
import com.esuiss.ui.components.ButtonVariant
import com.esuiss.ui.components.DropdownMenu
import com.esuiss.ui.components.DropdownMenuLabel
import com.esuiss.ui.components.DropdownMenuRadioGroup
import com.esuiss.ui.components.DropdownMenuRadioItem

Model Selector on mobile is built from the same parts as on the web: Dropdown Menu, Button. The example above is a static demo; connect it to your agent by rendering the same parts from your messages.

Installation

$ pnpm dlx @esuiss/ui@latest add dropdown-menu button
$ pnpm dlx @esuiss/ui@latest add dropdown-menu button --platform swift
$ pnpm dlx @esuiss/ui@latest add dropdown-menu button --platform kotlin

API Reference

See Dropdown Menu, Button.

NextContextPreviousSuggestion

On this page

  1. 01Installation
  2. 02Usage
  3. 03AI SDK
  4. 04API Reference
  5. 05Installation
  6. 06API Reference