The Select shadcn/ui is missing.
Single, multiple, and tags modes. Built-in search, virtualized lists, and full keyboard & screen-reader support — production-grade behavior in one copy-paste component.
Try it
npx shadcn@latest add https://gjs-select.gokhanyildiz.dev/r/gjs-select.jsonGet started
Installation
Add the component with the shadcn CLI — it drops select.tsx straight into your components/ui. No package to install, no styles to import. You own the code and edit it like any other file.
1. Run the shadcn CLI
npx shadcn@latest add https://gjs-select.gokhanyildiz.dev/r/gjs-select.json2. Use it
import { Select } from "@/components/ui/select"
const options = [
{ label: "Apple", value: "apple" },
{ label: "Banana", value: "banana" },
{ label: "Cherry", value: "cherry" },
]
export function Example() {
return (
<Select
options={options}
showSearch
allowClear
placeholder="Pick a fruit"
/>
)
}Showcase
Every mode, out of the box
Single, multiple, and tags modes; search, clear, optgroups, sizes, and built-in states — all driven by simple props.
Modes
Single by default, or mode="multiple | tags"
Search, clear & groups
showSearch · allowClear · optgroups
Sizes
size="small | middle | large"
States
disabled · loading · status=error
Patterns
Real-world patterns
Server and client rendering, debounced server-side search, and responsive tag overflow — the cases you actually ship.
Server & client components
The same Select rendered by a Server Component and a Client Component, side by side.
No 'use client' here. Options are prepared on the server and the Select is shipped as a client island.
'use client' with live state — selected: bun.
Debounced async search
showSearch · filterOption={false} · onSearch → fetch · loading — server-side filtering over a live API route.
Responsive tag overflow
maxTagCount="responsive" collapses tags that no longer fit into a +N pill as the control resizes.
← Drag the dashed box wider or narrower →
Playground
Try it live
Tweak the props and copy the generated code straight into your project.
Mode
Size
Options
<Select
options={options}
showSearch
allowClear
/>Reference
Props API
A curated set of the most-used props. The component also forwards refs and standard combobox ARIA attributes.
| Prop | Type | Default | Description |
|---|---|---|---|
options | SelectItem<V>[] | [] | Options or optgroups to render. { label, value, disabled? }. |
value / defaultValue | V | V[] | null | — | Controlled / uncontrolled selected value(s). |
onChange | (value, option) => void | — | Fires when the selection changes. |
mode | "multiple" | "tags" | — | Multi-select, or tags mode that creates new entries. |
showSearch | boolean | false* | Filterable search input inside the control (* on by default in multi). |
allowClear | boolean | false | Show a clear button to reset the value on hover. |
size | "small" | "middle" | "large" | "middle" | Control height and typography. |
status | "error" | "warning" | — | Validation status styling for the control. |
variant | "outlined" | "filled" | "borderless" | "outlined" | Visual style of the control. |
loading | boolean | false | Show a spinner and loading state. |
maxCount | number | — | Cap selections; remaining options disable at the limit. |
tokenSeparators | string[] | — | Split typed/pasted input into multiple tags. |
virtual | boolean | false | Windowed rendering for very long option lists. |
filterSort | (a, b, info) => number | — | Custom ordering for the filtered options. |
labelInValue | boolean | false | Emit { label, value } objects in onChange. |
fieldNames | { label, value, options } | — | Map custom keys on your option data. |