PRIZM 4.0DSTA
All components

Select

Choose one from a list of options.

stableBase UI Select

Preview

Code

tsx
import {
  Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
} from "@/components/ui/select";

export function Example() {
  return (
    <Select>
      <SelectTrigger>
        <SelectValue placeholder="Select severity" />
      </SelectTrigger>
      <SelectContent>
        <SelectItem value="Critical">Critical</SelectItem>
        <SelectItem value="High">High</SelectItem>
        <SelectItem value="Medium">Medium</SelectItem>
        <SelectItem value="Low">Low</SelectItem>
      </SelectContent>
    </Select>
  );
}

Props

PropTypeDefaultDescription
valuestringControlled selected value.
defaultValuestringUncontrolled initial value.
onValueChange(value: string) => voidCalled when the selection changes.
disabledbooleanfalseDisables the trigger.

Sub-components

SelectTriggerThe visible button that opens the popup.
PropTypeDefaultDescription
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().
SelectValueRenders the currently selected value inside the trigger.
PropTypeDefaultDescription
placeholderReactNodeShown when no value is selected.
SelectContentThe popup list of items. Portals to document body.
PropTypeDefaultDescription
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().
SelectItemAn individual option.
PropTypeDefaultDescription
valuestringThe value this item represents.
disabledbooleanfalseDisables this item.
classNamestringAdditional Tailwind classes, merged with the component's defaults via cn().

Built on Base UI Select. Keyboard: arrows navigate, Enter selects, type to search, Escape closes.

All components also accept standard HTML attributes for their root element (e.g. `id`, `aria-*`, `data-*`, event handlers) and forward `ref` where applicable.

Source

The full implementation of components/ui/select.tsx is below — copy it into your project and own it. Some components import the cn helper from lib/utils or other primitives; copy those too.

tsx
"use client";

import { cn } from "@/lib/utils";
import { Select as BaseSelect } from "@base-ui-components/react/select";
import { Check, ChevronDown } from "lucide-react";
import type { ComponentPropsWithoutRef, ReactNode } from "react";

export const Select = BaseSelect.Root;

export function SelectValue({
  placeholder,
  className,
  ...props
}: Omit<ComponentPropsWithoutRef<typeof BaseSelect.Value>, "children"> & {
  placeholder?: ReactNode;
}) {
  return (
    <BaseSelect.Value className={cn("data-[placeholder]:text-fg-subtle", className)} {...props}>
      {(value) => (value == null || value === "" ? placeholder : (value as ReactNode))}
    </BaseSelect.Value>
  );
}

export function SelectTrigger({
  className,
  children,
  ...props
}: ComponentPropsWithoutRef<typeof BaseSelect.Trigger>) {
  return (
    <BaseSelect.Trigger
      className={cn(
        "flex h-9 w-full items-center justify-between rounded-md border border-border bg-surface px-3 py-1 text-sm shadow-sm",
        "focus-visible:outline-1 focus-visible:outline-offset-0 focus-visible:outline-accent",
        "disabled:cursor-not-allowed disabled:opacity-50",
        "data-[placeholder]:text-fg-subtle",
        className,
      )}
      {...props}
    >
      {children}
      <BaseSelect.Icon className="text-fg-muted">
        <ChevronDown className="h-4 w-4" />
      </BaseSelect.Icon>
    </BaseSelect.Trigger>
  );
}

export function SelectContent({
  className,
  children,
  ...props
}: ComponentPropsWithoutRef<typeof BaseSelect.Popup> & { children?: ReactNode }) {
  return (
    <BaseSelect.Portal>
      <BaseSelect.Positioner sideOffset={4} alignItemWithTrigger={false} align="start">
        <BaseSelect.Popup
          className={cn(
            "z-50 max-h-[var(--available-height)] min-w-[var(--anchor-width)] overflow-y-auto",
            "rounded-md border border-border bg-surface-elevated p-1 shadow-md",
            "data-[starting-style]:opacity-0 data-[ending-style]:opacity-0 transition-opacity duration-150",
            className,
          )}
          {...props}
        >
          {children}
        </BaseSelect.Popup>
      </BaseSelect.Positioner>
    </BaseSelect.Portal>
  );
}

export function SelectItem({
  className,
  children,
  ...props
}: ComponentPropsWithoutRef<typeof BaseSelect.Item>) {
  return (
    <BaseSelect.Item
      className={cn(
        "relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm text-fg outline-none",
        "data-[highlighted]:bg-bg-muted",
        "data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
        className,
      )}
      {...props}
    >
      <BaseSelect.ItemIndicator className="absolute left-2 inline-flex items-center text-accent">
        <Check className="h-3.5 w-3.5" />
      </BaseSelect.ItemIndicator>
      <BaseSelect.ItemText>{children}</BaseSelect.ItemText>
    </BaseSelect.Item>
  );
}

JavaFX

Ships in the PRIZM JavaFX library for thick-client C3 apps as PrizmSelect<T> (extends ComboBox<T>). Run the gallery to see it natively.

java
import design.prizm.fx.controls.PrizmSelect<T>;

PrizmSelect()
PrizmSelect(ObservableList<T> items)
PropTypeDefaultDescription
itemsObservableList<T>The options — add via getItems().addAll(...).
valueObjectProperty<T>The selected item.

Thin subclass of ComboBox; trigger + popup styled by the .combo-box / .combo-box-popup rules in prizm.css. Mirrors components/ui/select.tsx.