npx shadcn@latest add https://sdk-components.thesqd.com/r/dropdown-v2.jsonimport { DropdownV2 } from "@/components/ui/dropdown-v2";import { useState } from "react";
import {
ChevronDownIcon,
LayoutGridIcon,
ListIcon,
KanbanIcon,
CalendarIcon,
TableIcon,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { DropdownV2 } from "@/components/ui/dropdown-v2";
const VIEWS = [
{ label: "Grid", icon: LayoutGridIcon },
{ label: "List", icon: ListIcon },
{ label: "Board", icon: KanbanIcon },
{ label: "Calendar", icon: CalendarIcon },
{ label: "Table", icon: TableIcon },
];
export function Example() {
const [selected, setSelected] = useState(0);
return (
<DropdownV2
trigger={
<Button variant="outline">
{`${VIEWS[selected].label} view`}
<ChevronDownIcon />
</Button>
}
items={VIEWS}
value={selected}
onValueChange={(v) => setSelected(v as number)}
/>
);
}DropdownV2 (single component — flat prop API)
├── trigger={<Button … />} (element that opens the menu)
├── items={DropdownV2ItemSpec[] | DropdownV2Group[]} (flat or grouped)
├── value={number | number[]} (selected index, or indices when multiple)
├── onValueChange={(v) => …} (v is a number, or number[] when multiple)
├── multiple (toggle several; menu stays open)
├── side / align / sideOffset (positioning)
└── className="…" (class override for the popup panel)
DropdownV2ItemSpec (each entry in a flat items array):
├── { label, icon?, hint?, disabled?, onSelect?, closeOnClick? }
└── { label, icon?, items, search?, empty? } (a flyout submenu; `search` filters it)
DropdownV2Group (pass an array of these for section headings + separators):
├── { heading?, items: DropdownV2ItemSpec[] } (value indexes the flattened items)
└── { content: ReactNode } (rich block, e.g. a header card)
Need an always-open inline panel or a custom layout? The compound slot exports
— DropdownMenu, DropdownTrigger, DropdownContent, DropdownSub, MenuItem, plus Dropdown /
DropdownLabel / DropdownSeparator — remain available from the same file.DropdownV2
| Prop | Type | Default | Description |
|---|---|---|---|
trigger | ReactElement | — | Element that opens the menu (e.g. a `<Button>`). |
items | DropdownV2ItemSpec[] | DropdownV2Group[] | — | A flat list of rows, or `{ heading?, items?, content? }` groups drawn with headings and separators. |
value / defaultValue | number | number[] | — | Selected index (single) or indices (multiple), across the flattened top-level rows. Omit for an action menu. |
onValueChange | (value) => void | — | Fires with the next selection. |
multiple | boolean | false | Toggle several rows; the menu stays open. |
side / align / sideOffset | positioning | — | Where the popup opens against the trigger. |
backdrop | boolean | false | Dim and slightly blur the app behind the open menu — a lighter take on the Drawer's overlay. The trigger stays sharp (a hole is cut over it); a click on the backdrop closes the menu. |
className | string | — | Class override for the popup panel. |
DropdownV2ItemSpec (each `items` entry)
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | The row's text. Also what a submenu's `search` matches. |
icon | IconComponent | — | Optional leading icon component. |
hint | string | — | Right-aligned muted text — a date, a count, a shortcut. |
onSelect | () => void | — | Fired when the row is chosen. |
disabled | boolean | — | Disable the row (or the submenu's trigger). |
closeOnClick | boolean | — | Override close-on-select. Default: single closes, multi stays open; submenu rows close. |
items | DropdownV2ItemSpec[] | — | Makes the row a flyout SUBMENU of these rows (they nest). Submenu rows are actions — each fires its own `onSelect` and closes the whole menu; they never join `value`. |
search | boolean | string | — | Submenus only — a search field across the top that narrows the rows by `label`. Pass a string for the placeholder. |
empty | string | "Nothing here." | Submenus only — what an empty submenu says. |