Made of something. Aged ivory shells, smoky glass and a restrained violet jewel.

The moment. The shells part to reveal a portalled option list, then close around the selected path. Keyboard, typeahead and focus restoration use Radix Select.

Yours to adapt. Copy the component source, styles and materials. Functional text stays live, effects respect reduced motion, and the artwork requires no remote hosting.

Try it

Open the shells and choose a path using the pointer, arrow keys or typeahead.

Install

Add it with the shadcn CLI, or copy the source manually.

Release candidate: public installation becomes available after deployment. Use an existing React 19 project with shadcn initialized and a components.json file. The CLI installs the source, CSS, embedded materials, MIT licence and font notices together.

Terminal
npx shadcn@latest add https://seanportfol.io/r/grimkit-veil-select.json
Prefer a namespace? Register the registry once.
Terminal
npx shadcn@latest registry add @seanlynch=https://seanportfol.io/r/{name}.json
Terminal
npx shadcn@latest add @seanlynch/grimkit-veil-select

Usage

Copy this example into a separate file, not over the installed component. The @/ alias points to your source root. In Next.js this is a Client Component; Vite also accepts the directive. Replace demonstration actions with your application logic.

components/examples/veil-select-demo.tsx
"use client";

import { VeilSelect } from "@/components/grimkit/veil-select";

export default function Example() {
  return <VeilSelect label="Choose a path" name="path" defaultValue="seer" options={[{value:"seer",label:"Path of the seer"},{value:"artisan",label:"Path of the artisan"},{value:"ranger",label:"Path of the ranger"}]} />;
}

API Reference

Props on Veil Select. Consult the included TypeScript source for supported native attributes.

PropTypeDefault
labelAccessible control label.string–
optionsOptions with value, label and optional disabled state. See the exported option type for additional fields.readonly VeilOption[]–
valueControlled value. Update it in the change callback; visual effects never delay value changes.string–
defaultValueInitial uncontrolled value. Do not combine with value.string''
onValueChangeReports a requested value change immediately.(value:string)=>void–
openControlled visibility.boolean–
defaultOpenInitial uncontrolled visibility.booleanfalse
onOpenChangeReports opening or dismissal, including keyboard dismissal.(open:boolean)=>void–
nameNative form field name.string–
formID of the associated form.string–
requiredRequires a selection for form submission.booleanfalse
disabledDisables user interaction and cancels transient effects.booleanfalse
placeholderOptional placeholder.string'Choose a path'
effectsAuto honours reduced motion; off suppresses decorative motion without changing values.'auto'|'off''auto'
classNameAdditional surface class; does not replace material styles.string''

Information

Category
GrimKit
Files
  • components/grimkit/veil-select.tsx
  • components/grimkit/veil-select.css
  • components/grimkit/veil-select-materials.css
  • components/grimkit/LICENSE.txt
  • components/grimkit/Saira-OFL.txt
  • components/grimkit/JetBrainsMono-OFL.txt
Dependencies
@radix-ui/react-select@^2.3.7
Compatibility
React 19, TypeScript, CSS imports, Modern browsers
Version
0.3.0
Updated
Sep 24, 2026
Registry
grimkit-veil-select