Skip to content

Select

Single-select dropdown with a hidden native select and listbox options.

Primitive · form

Terminal window
npx shadcn@latest add https://ndigo.dev/r/select.json

To use the shorter @ndigo/select form, configure the namespace in components.json.

Source Target Type
registry/ui/select/nd-select.ts @ui/nd-select/nd-select.ts registry:ui
registry/ui/select/nd-select.css @ui/nd-select/nd-select.css registry:file

See this component rendered live on the live examples page.

Registry: Ndigo element foundation. Packages: @zag-js/select@~1.47.0, @zag-js/collection@~1.47.0 (installed automatically).

<nd-select> derives its collection from the authored items and keeps a hidden native <select> in sync, so the value submits with the form.

<nd-select name="fruit" value="apple">
<label data-part="label">Fruit</label>
<div data-part="control">
<button data-part="trigger" type="button">
<span data-part="value-text"></span>
<span data-part="indicator">v</span>
</button>
<button data-part="clear-trigger" type="button">Clear</button>
</div>
<div data-part="positioner">
<div data-part="content">
<div data-part="item" data-value="apple">
<span data-part="item-text">Apple</span><span data-part="item-indicator">✓</span>
</div>
<div data-part="item" data-value="banana">
<span data-part="item-text">Banana</span><span data-part="item-indicator">✓</span>
</div>
</div>
</div>
</nd-select>

A root wrapper, hidden <select>, and placeholder value text are created on connect. Items live directly inside the content listbox.

Attribute Type Description
value string Initial selected value
name string Form field name for the hidden select
placeholder string Value text when nothing is selected
disabled boolean Disable the select
readonly boolean Keep the value but block changes
required boolean Mark the hidden select required
invalid boolean Mark the select invalid
open boolean Controlled open state; reflected by the element
  • nd-value-change — detail: { value: string[] }; data-value mirrors the joined values.
  • nd-open-change — detail: { open: boolean }.
  • select(value) — select one value programmatically.

The trigger is a combobox with aria-expanded/aria-controls; the content is a listbox and items are options. Arrow keys move the highlight, Enter selects, and Escape closes. The hidden native select carries the form value and is labelled by the visible label.

Import nd-select.css after the tokens. The trigger uses the surface/border tokens, the content the raised surface and shadow, and the selected item the accent tokens.