Components
Select
Select on Base UI: ink trigger, paper popup with a 1px rule, ink check on the chosen item; no shadow or radius.
Preview
Install
bash
npx shadcn add @eloquent/selectUsage
tsx
import {
Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue,
} from "@/components/ui/select";
const sections = [
{ label: "World", value: "world" },
{ label: "Business", value: "business" },
];
<Select items={sections} defaultValue="business">
<SelectTrigger aria-label="Section">
<SelectValue placeholder="Choose a section" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Sections</SelectLabel>
{sections.map((s) => <SelectItem key={s.value} value={s.value}>{s.label}</SelectItem>)}
</SelectGroup>
</SelectContent>
</Select>Pass items to Select so the trigger shows the chosen label before the popup has opened. Give the trigger a name with aria-label, aria-labelledby or a Field.
States
Placeholder
Disabled
Choose an edition to continue.
| State | Treatment |
|---|---|
| Default | 1px ink border, paper fill, ink chevron, 44px high; the placeholder is halftone |
| Press, open | tint-1 fill. No hover effect |
| Focus | 2px ink outline, 2px offset |
| Invalid | 2px ink underline, with FieldError giving the ink icon and message |
| Disabled | Halftone text and border, cursor-not-allowed |
| Item highlighted | Ink fill, paper text (it follows the keyboard and the pointer) |
| Item selected | Ink check at the start of the row |
| Item disabled | Halftone text, cursor-not-allowed |
Keyboard
| Key | Action |
|---|---|
| Tab / Shift+Tab | Move focus to and from the trigger (a disabled select is skipped) |
| Enter / Space / Arrow Down / Arrow Up | Open the popup |
| Arrow Up / Down | Move the highlight |
| Home / End | Highlight the first or last item |
| Letters | Jump to the matching item (typeahead) |
| Enter | Choose the highlighted item and close |
| Esc | Close without changing the value; focus returns to the trigger |
Vietnamese
Ink adaptation
Upstream shadcn's radius, shadow, focus ring glow and muted hover fill are removed. The popup is paper with a 1px ink rule, and it opens below the trigger (alignItemWithTrigger is off by default, unlike Base UI). The trigger's size prop is dropped to keep a 44px hit target. Fades use opacity only and stop under prefers-reduced-motion. Built on Base UI Select.