Model Selector
Seletor de modelo no estilo Cmd+K construído sobre Dialog + Command, com logos de provider e teclas de atalho.
Visão geral
ModelSelector é um seletor de modelo flutuante. Ele envolve um Command palette com um Dialog para que os usuários possam buscar, filtrar e selecionar um modelo de uma lista longa. Helpers como ModelSelectorLogo e ModelSelectorLogoGroup puxam ícones de provider do models.dev, então uma lista longa de modelos do OpenRouter ou AI Gateway pode ser navegada visualmente.
Use como a troca de modelo na casca do chat - seja como um botão discreto na toolbar ou como um atalho global Cmd+K.
Preview
'use client';import { ModelSelector, ModelSelectorContent, ModelSelectorTrigger,} from '@gremorie/rx-ai';import { Button } from '@gremorie/rx-forms';export function ModelSelectorPreview() { return ( <ModelSelector> <ModelSelectorTrigger asChild> <Button variant="outline">Select model</Button> </ModelSelectorTrigger> <ModelSelectorContent> <div className="p-4 text-sm"> <p className="font-medium">Pick a model</p> <p className="mt-1 text-muted-foreground"> Models would be listed here. </p> </div> </ModelSelectorContent> </ModelSelector> );}Anatomia
ModelSelector
├─ ModelSelectorTrigger modelo selecionado (logo + nome)
└─ ModelSelectorContent command palette (popover ou dialog)
├─ ModelSelectorInput busca
├─ ModelSelectorEmpty
└─ ModelSelectorList
└─ ModelSelectorGroup por provider
└─ ModelSelectorItem logo + nome + atalhoInstalação
bash npx gremorie@latest add rx-model-selector bash pnpm dlx gremorie@latest add rx-model-selector
bash yarn dlx gremorie@latest add rx-model-selector
bash bunx --bun gremorie@latest add rx-model-selector
Uso
import {
ModelSelector,
ModelSelectorTrigger,
ModelSelectorContent,
ModelSelectorInput,
ModelSelectorList,
ModelSelectorGroup,
ModelSelectorItem,
ModelSelectorLogo,
ModelSelectorName,
} from "@gremorie/rx-ai";
export function Example() {
return (
<ModelSelector>
<ModelSelectorTrigger>{currentModel}</ModelSelectorTrigger>
<ModelSelectorContent title="Choose a model">
<ModelSelectorInput placeholder="Search models..." />
<ModelSelectorList>
<ModelSelectorGroup heading="Frontier">
<ModelSelectorItem value="anthropic/claude-opus-4">
<ModelSelectorLogo provider="anthropic" />
<ModelSelectorName>Claude Opus 4</ModelSelectorName>
</ModelSelectorItem>
</ModelSelectorGroup>
</ModelSelectorList>
</ModelSelectorContent>
</ModelSelector>
);
}A edição Angular deste componente é distribuída a partir do source hoje (veja o workbench para o lado a lado); sua entrada no registry vem a seguir.
API
<ModelSelector>
Envolve Dialog. Use open / onOpenChange para estado controlado.
Estende ComponentProps<typeof Dialog>.
<ModelSelectorTrigger>
DialogTrigger. Use asChild para compor com qualquer botão.
<ModelSelectorContent>
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | "Model Selector" | Título acessível (sr-only) do dialog. |
DialogContent com padding zero e um Command dentro.
Sub-componentes de Command
Esses wrappers finos encaminham as props de Command*:
| Component | Envolve |
|---|---|
ModelSelectorDialog | CommandDialog (modo dialog Cmd+K completo) |
ModelSelectorInput | CommandInput (mais alto py-3.5) |
ModelSelectorList | CommandList |
ModelSelectorEmpty | CommandEmpty |
ModelSelectorGroup | CommandGroup (aceita heading) |
ModelSelectorItem | CommandItem |
ModelSelectorSeparator | CommandSeparator |
ModelSelectorShortcut | CommandShortcut (para dicas no estilo Cmd+1) |
<ModelSelectorLogo>
| Prop | Type | Default | Description |
|---|---|---|---|
provider | string | - | Obrigatório. Puxado de models.dev/logos/{provider}.svg. Cobre a maioria dos principais providers (anthropic, openai, google, mistral, deepseek, xai, ...). |
Renderizado como um img minúsculo (12 x 12), invertido no dark mode.
<ModelSelectorLogoGroup>
Envolve múltiplos ModelSelectorLogos com espaçamento negativo para sobrepô-los (útil para routers que abrangem vários providers).
<ModelSelectorName>
span com flex-1 truncate text-left. Use para o nome do modelo dentro de um item.
Composição
<ModelSelector>detém o estado do dialog.<ModelSelectorTrigger>é o handle da toolbar.<ModelSelectorContent>é o corpo do dialog que hospeda umCommand.<ModelSelectorInput>+<ModelSelectorList>+<ModelSelectorGroup>+<ModelSelectorItem>formam a lista buscável.<ModelSelectorLogo>/<ModelSelectorName>/<ModelSelectorShortcut>estruturam cada item.
Variações
Lista agrupada com atalhos
Agrupe por provider; exponha Cmd+1, Cmd+2, etc. para as escolhas do topo.
<ModelSelectorContent title="Switch model">
<ModelSelectorInput placeholder="Search..." />
<ModelSelectorList>
<ModelSelectorGroup heading="Pinned">
<ModelSelectorItem value="anthropic/claude-opus-4">
<ModelSelectorLogo provider="anthropic" />
<ModelSelectorName>Claude Opus 4</ModelSelectorName>
<ModelSelectorShortcut>1</ModelSelectorShortcut>
</ModelSelectorItem>
<ModelSelectorItem value="openai/gpt-5">
<ModelSelectorLogo provider="openai" />
<ModelSelectorName>GPT-5</ModelSelectorName>
<ModelSelectorShortcut>2</ModelSelectorShortcut>
</ModelSelectorItem>
</ModelSelectorGroup>
<ModelSelectorSeparator />
<ModelSelectorGroup heading="All models">
{models.map((m) => (
<ModelSelectorItem key={m.id} value={m.id}>
<ModelSelectorLogo provider={m.provider} />
<ModelSelectorName>{m.name}</ModelSelectorName>
</ModelSelectorItem>
))}
</ModelSelectorGroup>
</ModelSelectorList>
</ModelSelectorContent>Itens de router com logos sobrepostos
Para agregadores (OpenRouter, AI Gateway), mostre cada provider por trás do router em um grupo de logos.
<ModelSelectorItem value="openrouter/anthropic/claude-opus-4">
<ModelSelectorLogoGroup>
<ModelSelectorLogo provider="openrouter" />
<ModelSelectorLogo provider="anthropic" />
</ModelSelectorLogoGroup>
<ModelSelectorName>OpenRouter - Claude Opus 4</ModelSelectorName>
</ModelSelectorItem>Dialog global Cmd+K
Use ModelSelectorDialog (envolve CommandDialog) para um seletor de modelo totalmente destacado, invocado pelo teclado.
const [open, setOpen] = useState(false);
useEffect(() => {
const onKey = (e: KeyboardEvent) => {
if (e.key === 'k' && (e.metaKey || e.ctrlKey)) {
e.preventDefault();
setOpen((o) => !o);
}
};
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
}, []);
<ModelSelectorDialog open={open} onOpenChange={setOpen}>
<ModelSelectorInput placeholder="Switch model..." />
<ModelSelectorList>{/* items */}</ModelSelectorList>
</ModelSelectorDialog>;Acessibilidade
- Teclado: o Command palette trata Arrow Up / Down para navegação, Enter para selecionar, Esc para fechar. O trigger participa da ordem normal de Tab.
- ARIA:
ModelSelectorContentsempre renderiza umDialogTitle(sr-only por padrão) para que o dialog tenha um nome acessível. As imagens deModelSelectorLogocarregam umaltno formato"{provider} logo". - Leitores de tela: mantenha
ModelSelectorNamepreenchido para que cada item anuncie com o nome do modelo; o logo é tratado como suplementar. - Gestão de foco: o Dialog prende o foco enquanto aberto e o retorna ao trigger no fechamento.
Relacionados
- PromptInput - host típico do trigger de modelo
- Context - combine com o selector para mostrar o usage do modelo atual
- OpenInChat - variante de kickoff que inclui pré-seleção de modelo