Select (Native)

A styleable select built on Base UI's listbox — full keyboard support and typeahead, tokened to match every other control.

Colors

Sizes

Real use · shipping region

Using Select (Native)

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path is complete for Select (Native) — it needs no JavaScript, so the classes below are the whole story.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class select, with 13 modifiers:

  • .select
  • .select-accent
  • .select-error
  • .select-info
  • .select-lg
  • .select-md
  • .select-neutral
  • .select-primary
  • .select-secondary
  • .select-sm
  • .select-success
  • .select-warning
  • .select-xl
  • .select-xs

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { Select } from "@wizeworks/silicaui-react";

Props

SelectItemProps
PropTypeRequiredDescription
valueunknownyesThe value stored when this item is chosen.
childrenReact.ReactNodeno—
SelectProps
PropTypeRequiredDescription
valueunknownnoControlled value (array when multiple).
defaultValueunknownnoUncontrolled initial value.
onValueChange(value: unknown, eventDetails?: unknown) => voidnoFires with the newly-selected value.
multiplebooleannoAllow selecting multiple items (value becomes an array).
itemsSelectItemsnoValue→label map used to render the trigger's selected label (and, if no children are given, to auto-render the options). A record ({value: label}) or an array ([{ value, label }]).
namestringnoField name for form submission.
disabledbooleanno—
requiredbooleanno—
readOnlybooleanno—
placeholderReact.ReactNodenoShown on the trigger while nothing is selected.
colorSelectColornoAccent for the trigger border + focus ring (shares NativeSelect colors).
sizeSelectSizenoTrigger height; matches same-size Inputs/Buttons.
sideSelectSideno—
alignSelectAlignno—
sideOffsetnumberno—
alignItemWithTriggerbooleannoOverlay the selected item on the trigger (native-select style). Default false.
classNamestringnoClass for the trigger button.
popupClassNamestringnoClass for the popup surface.
popupPropsReact.ComponentProps<typeof BaseSelect.Popup> & { [key: `data-${string}`]: string; }noExtra props spread onto the popup surface.
"aria-label"stringnoAccessible name when there's no associated visible label.
"aria-labelledby"stringno—
idstringno—
childrenReact.ReactNodenoSelectItem/SelectGroup/SelectSeparators. Omit to auto-render items.
anchorBasePositionerProps["anchor"]noWhat to position against. Defaults to the component's own trigger.
positionMethodBasePositionerProps["positionMethod"]noabsolute (default) or fixed. Use fixed to escape a clipping ancestor.
alignOffsetBasePositionerProps["alignOffset"]noOffset along the alignment axis, in px. Pairs with align.
collisionBoundaryBasePositionerProps["collisionBoundary"]noThe element the popup must stay inside. Defaults to the viewport — set it to a scroll container so the popup collides with the panel, not the window.
collisionPaddingBasePositionerProps["collisionPadding"]noInset from the collision boundary, in px.
collisionAvoidanceBasePositionerProps["collisionAvoidance"]noWhich collision strategy runs per axis (flip, shift, none).
stickyBasePositionerProps["sticky"]noKeep the popup glued to the anchor while it scrolls out of view.
arrowPaddingBasePositionerProps["arrowPadding"]noMinimum distance from the popup's corner to the arrow, in px.
disableAnchorTrackingBasePositionerProps["disableAnchorTracking"]noStop re-measuring when the anchor moves. Cheaper, but goes stale.

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import { NativeSelect } from "@wizeworks/silicaui-react";
import { Section, Row, Stack } from "../lib/Section";
import { SIZES } from "../lib/data";

export function SelectDemo() {
    return (
        <>
            <Section title="Colors">
                <Stack className="max-w-md">
                    <NativeSelect defaultValue="">
                        <option value="" disabled>
                            Pick a framework…
                        </option>
                        <option>React</option>
                        <option>Svelte</option>
                        <option>Vue</option>
                        <option>Solid</option>
                    </NativeSelect>
                    <NativeSelect color="primary" defaultValue="React">
                        <option>React</option>
                        <option>Svelte</option>
                        <option>Vue</option>
                    </NativeSelect>
                    <NativeSelect color="success" defaultValue="React">
                        <option>React</option>
                        <option>Svelte</option>
                    </NativeSelect>
                    <NativeSelect color="error" defaultValue="React">
                        <option>React</option>
                        <option>Svelte</option>
                    </NativeSelect>
                    <NativeSelect disabled defaultValue="React">
                        <option>React</option>
                    </NativeSelect>
                </Stack>
            </Section>

            <Section title="Sizes">
                <Row>
                    {SIZES.map((size) => (
                        <NativeSelect key={size} size={size} defaultValue={size}>
                            <option>{size}</option>
                        </NativeSelect>
                    ))}
                </Row>
            </Section>

            <Section title="Real use · shipping region">
                <div className="grid max-w-sm gap-3 rounded-box border border-base-300 bg-base-100 p-5 shadow-sm">
                    <label className="flex flex-col gap-1.5 text-sm">
                        Country
                        <NativeSelect color="primary" defaultValue="US">
                            <option value="US">United States</option>
                            <option value="CA">Canada</option>
                            <option value="MX">Mexico</option>
                            <option value="UK">United Kingdom</option>
                        </NativeSelect>
                    </label>
                    <label className="flex flex-col gap-1.5 text-sm">
                        Shipping speed
                        <NativeSelect defaultValue="standard">
                            <option value="standard">Standard (5–7 days)</option>
                            <option value="express">Express (2–3 days)</option>
                            <option value="overnight">Overnight</option>
                        </NativeSelect>
                    </label>
                </div>
            </Section>
        </>
    );
}

Vanilla — node tree to HTML

Select — a native <select>; options come from props.options (or child nodes). Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("Select", "select", { /* props */ });
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "select select-primary" rather than passing a colour as a prop.

Takes children
no
Hydrated by
nothing — this one is static markup

The full API for Select (Native), on every path, is available through the Silica MCP server.