Skip to content
Notra logoNotra UI
Esc
↑↓navigate↵open⌘Jpreview
On this page

Select

A Base UI select with a Depth button trigger and a popup that opens below it.

The trigger uses the same surface as the outline button. The list opens below it with a 4px gap, rounded corners, a subtle gradient and layered shadows.

import { useId } from "react";

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

import { FREQUENCY_OPTIONS } from "../constants/select";

export default function SelectDemo() {
  const id = useId();

  return (
    <div className="flex min-h-80 flex-wrap items-start justify-center gap-8 p-8">
      <div className="flex flex-col gap-2">
        <label className="text-sm" htmlFor={`${id}-frequency`}>
          Frequency
        </label>
        <Select defaultValue="weekly" items={FREQUENCY_OPTIONS}>
          <SelectTrigger className="w-48" id={`${id}-frequency`}>
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            <SelectGroup>
              <SelectLabel>Frequency</SelectLabel>
              <SelectItem value="daily">Daily</SelectItem>
              <SelectItem value="weekly">Weekly</SelectItem>
              <SelectItem value="monthly">Monthly</SelectItem>
            </SelectGroup>
            <SelectSeparator />
            <SelectItem disabled value="custom">
              Custom
            </SelectItem>
          </SelectContent>
        </Select>
      </div>
      <div className="flex flex-col gap-2">
        <label className="text-sm" htmlFor={`${id}-inline`}>
          Compact property
        </label>
        <Select defaultValue="weekly" items={FREQUENCY_OPTIONS}>
          <SelectTrigger id={`${id}-inline`} size="sm" variant="ghost">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {FREQUENCY_OPTIONS.map((option) => (
              <SelectItem key={option.value} value={option.value}>
                {option.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>
    </div>
  );
}

Installation

$ bunx --bun shadcn@latest add @notra/notra-select

This replaces components/ui/select.tsx and installs the Notra button and shared dropdown styles. Use a shadcn project on Base UI and Tailwind CSS v4.

Usage

Pass items to show option labels in the trigger rather than their raw values.

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

<Select
  defaultValue="weekly"
  items={[
    { value: "daily", label: "Daily" },
    { value: "weekly", label: "Weekly" },
  ]}
>
  <SelectTrigger aria-label="Frequency" className="w-48">
    <SelectValue />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="daily">Daily</SelectItem>
    <SelectItem value="weekly">Weekly</SelectItem>
  </SelectContent>
</Select>

Positioning and variants

The list is start-aligned and does not overlap the trigger or flip above it. When space below is limited, it scrolls within the available height.

Use size="sm" for a compact trigger or variant="ghost" to remove the field surface for inline property editing. The popup still opens below the trigger.

Arrow keys move between options, Enter selects and Escape closes the list. Disabled options are skipped. Popup motion is disabled when reduced motion is enabled.