Model Select
A searchable, groupable model picker with capability filters and controlled pinning.
A searchable, groupable model picker. It is fully controlled — you own the value (and, optionally, the pinned list) and update them from onChange / onTogglePin. Each option is a slot-driven ModelSelectOption, so the icons, capability glyphs, badges, and detail rows are host-rendered and stay framework-agnostic.
Import
1import { ModelSelect } from "@yuhuanowo/yunui/ai";Basic
Hold the selected id in state and pass it back via onChange. Pinning is optional and controlled the same way — supply pinned plus onTogglePin. The trigger width comes from className (defaults to w-64).
Basic
Options
Every entry is a ModelSelectOption. Beyond id, label, and group, the rest are optional slots that let the host render whatever it needs:
groupLabel/groupIcon— the heading and icon shown for the option's group.searchText— extra text (aliases, the raw id) folded into the search match.icon— the leading glyph for the row, typically a<ModelIcon>or<ProviderIcon>.badges— trailing capability glyphs (e.g.<CapabilityIcon>) and status markers.detail— a secondary line under the label for the id, aliases, or specs.meta— a far-right slot for anything aligned to the row's end.disabled— renders the option but blocks selection.
Capability glyphs come from YunUI's shared capability config (CapabilityIcon), so the picker, filter chips, and standalone badges can't drift on icon or color.
Filtering and pinning
Pass filters as ModelSelectFilter[] — each has a key, a node (the chip), an optional title, and a match predicate run against every option. pinned plus onTogglePin surface a pinned group at the top, and renderFooter receives the visible count. Override any built-in copy through labels (placeholder, search, all, pinned, noResults, …).
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | — | |
| filterResetKey | string | number | — | Bump this to imperatively clear the internal search + provider/capability filters WITHOUT remounting the panel (so it stays open and doesn't lose scroll/focus). Use it when the option set is swapped out from under the filters — e.g. toggling a browse mode — where a carried-over filter would otherwise empty the new list. |
| filters | ModelSelectFilter[] | — | Capability filter chips. |
| labels | ModelSelectLabels | — | |
| onChange* | (id: string) => void | — | |
| onTogglePin | ((id: string) => void) | — | |
| options* | ModelSelectOption[] | — | |
| pinned | string[] | — | Controlled pinned ids. Pass with `onTogglePin` to show the pin column. |
| renderFooter | ((count: number) => ReactNode) | — | Optional footer bar; receives the current (filtered) result count. |
| renderHeader | (() => ReactNode) | — | Rendered at the very TOP of the open panel, above the search box — and always visible, even when the list is empty (unlike renderFooter, which hides on an empty result set). Use it for a domain toolbar that must stay reachable, e.g. a browse-mode switch above the picker. |
| value* | string | — | Selected option id. |