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-selectThis 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.