beUI Pro for mobile is live — 50 React Native blocks and screens
Animated Dropdown
1 variant
A composable dropdown with a corner-origin surface morph, a spring-driven focus surface, nested menus, collision handling, and complete keyboard navigation.
Animated dropdown
index.tsxFour dropdown compositions demonstrating the shared animated focus surface across pointer and keyboard navigation, controlled selection, text triggers, and nested states.
TSXcomponents/previews/premium/animated-dropdown-preview.tsx
"use client";
import {
Archive,
Bell,
BookOpen,
Building2,
CheckCircle2,
ChevronDown,
CircleHelp,
Copy,
CreditCard,
Ellipsis,
FileCode2,
FolderOpen,
LifeBuoy,
Newspaper,
Pencil,
Settings2,
Trash2,
UserRound,
} from "lucide-react";
import { useState } from "react";
import { Button } from "@/components/motion/button/base";
import {
AnimatedDropdown,
AnimatedDropdownCheckboxItem,
AnimatedDropdownContent,
AnimatedDropdownGroup,
AnimatedDropdownItem,
AnimatedDropdownItemDescription,
AnimatedDropdownItemIcon,
AnimatedDropdownItemText,
AnimatedDropdownLabel,
AnimatedDropdownRadioGroup,
AnimatedDropdownRadioItem,
AnimatedDropdownSeparator,
AnimatedDropdownShortcut,
AnimatedDropdownSub,
AnimatedDropdownSubContent,
AnimatedDropdownSubTrigger,
AnimatedDropdownTrigger,
} from "@/components/premium/animated-dropdown";
const statuses = [
{ value: "draft", label: "Draft" },
{ value: "review", label: "In review" },
{ value: "published", label: "Published" },
] as const;
export function AnimatedDropdownPreview() {
const [notifications, setNotifications] = useState(true);
const [status, setStatus] = useState("draft");
const activeStatus =
statuses.find((option) => option.value === status) ?? statuses[0];
return (
<div className="flex min-h-[480px] w-full items-center justify-center p-6">
<div className="flex flex-wrap items-center justify-center gap-3">
<AnimatedDropdown>
<AnimatedDropdownTrigger asChild>
<Button
variant="outline"
pressScale={1}
whileHover={{ scale: 1 }}
className="group min-w-52 justify-between bg-background px-3.5"
>
<span className="inline-flex min-w-0 items-center gap-2.5">
<span className="grid size-6 shrink-0 place-items-center rounded-md bg-muted">
<Building2
aria-hidden
className="size-3.5 text-muted-foreground"
/>
</span>
<span className="truncate">Acme workspace</span>
</span>
<ChevronDown
aria-hidden
className="size-4 text-muted-foreground transition-transform duration-300 group-data-[state=open]:rotate-180"
/>
</Button>
</AnimatedDropdownTrigger>
<AnimatedDropdownContent align="end" className="min-w-72" showArrow>
<AnimatedDropdownLabel>Workspace</AnimatedDropdownLabel>
<AnimatedDropdownGroup>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<UserRound />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>
Profile
<AnimatedDropdownItemDescription>
Personal details and preferences
</AnimatedDropdownItemDescription>
</AnimatedDropdownItemText>
<AnimatedDropdownShortcut>⌘P</AnimatedDropdownShortcut>
</AnimatedDropdownItem>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<CreditCard />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>
Billing
<AnimatedDropdownItemDescription>
Plan, invoices, and payment methods
</AnimatedDropdownItemDescription>
</AnimatedDropdownItemText>
</AnimatedDropdownItem>
</AnimatedDropdownGroup>
<AnimatedDropdownSeparator />
<AnimatedDropdownCheckboxItem
checked={notifications}
onCheckedChange={(checked) => setNotifications(checked === true)}
onSelect={(event) => event.preventDefault()}
>
<AnimatedDropdownItemText>
Activity notifications
</AnimatedDropdownItemText>
<Bell
aria-hidden
className="size-4 shrink-0 text-muted-foreground"
/>
</AnimatedDropdownCheckboxItem>
<AnimatedDropdownSub>
<AnimatedDropdownSubTrigger>
<AnimatedDropdownItemIcon>
<FolderOpen />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Open recent</AnimatedDropdownItemText>
</AnimatedDropdownSubTrigger>
<AnimatedDropdownSubContent className="min-w-52">
<AnimatedDropdownLabel>Recent projects</AnimatedDropdownLabel>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<FileCode2 />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>
Project Alpha
</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<FileCode2 />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>
Project Beta
</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<Ellipsis />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>
More projects
</AnimatedDropdownItemText>
</AnimatedDropdownItem>
</AnimatedDropdownSubContent>
</AnimatedDropdownSub>
<AnimatedDropdownSeparator />
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<CircleHelp />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Help center</AnimatedDropdownItemText>
<AnimatedDropdownShortcut>?</AnimatedDropdownShortcut>
</AnimatedDropdownItem>
<AnimatedDropdownItem disabled>
<AnimatedDropdownItemIcon>
<Settings2 />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>
Enterprise controls
<AnimatedDropdownItemDescription>
Available on Enterprise
</AnimatedDropdownItemDescription>
</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<CheckCircle2 />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>
Mark all as reviewed
</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownSeparator />
<AnimatedDropdownItem destructive>
<AnimatedDropdownItemIcon className="text-current">
<Trash2 />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>
Delete workspace
</AnimatedDropdownItemText>
</AnimatedDropdownItem>
</AnimatedDropdownContent>
</AnimatedDropdown>
<AnimatedDropdown>
<AnimatedDropdownTrigger asChild>
<Button
aria-label="Open actions"
variant="outline"
size="icon"
pressScale={1}
whileHover={{ scale: 1 }}
className="bg-background"
>
<Ellipsis aria-hidden className="size-4" />
</Button>
</AnimatedDropdownTrigger>
<AnimatedDropdownContent align="end" className="min-w-48">
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<Pencil />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Rename</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<Copy />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Duplicate</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<Archive />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Archive</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownSeparator />
<AnimatedDropdownItem destructive>
<AnimatedDropdownItemIcon className="text-current">
<Trash2 />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Delete</AnimatedDropdownItemText>
</AnimatedDropdownItem>
</AnimatedDropdownContent>
</AnimatedDropdown>
<AnimatedDropdown>
<AnimatedDropdownTrigger asChild>
<Button
variant="outline"
pressScale={1}
whileHover={{ scale: 1 }}
className="group min-w-40 justify-between bg-background px-3.5"
>
<span className="inline-flex items-center gap-2">
<span
aria-hidden
className="size-1.5 rounded-full bg-foreground"
/>
{activeStatus.label}
</span>
<ChevronDown
aria-hidden
className="size-4 text-muted-foreground transition-transform duration-300 group-data-[state=open]:rotate-180"
/>
</Button>
</AnimatedDropdownTrigger>
<AnimatedDropdownContent className="min-w-48">
<AnimatedDropdownLabel>Status</AnimatedDropdownLabel>
<AnimatedDropdownRadioGroup
value={status}
onValueChange={setStatus}
>
{statuses.map((option) => (
<AnimatedDropdownRadioItem
key={option.value}
value={option.value}
onSelect={(event) => event.preventDefault()}
>
<AnimatedDropdownItemText>
{option.label}
</AnimatedDropdownItemText>
</AnimatedDropdownRadioItem>
))}
</AnimatedDropdownRadioGroup>
</AnimatedDropdownContent>
</AnimatedDropdown>
<AnimatedDropdown>
<AnimatedDropdownTrigger asChild>
<button
type="button"
className="inline-flex h-10 items-center rounded-lg px-2.5 font-medium text-foreground text-sm transition-colors hover:bg-muted data-[state=open]:bg-muted"
>
Resources
</button>
</AnimatedDropdownTrigger>
<AnimatedDropdownContent className="min-w-48">
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<BookOpen />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Documentation</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<Newspaper />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Changelog</AnimatedDropdownItemText>
</AnimatedDropdownItem>
<AnimatedDropdownItem>
<AnimatedDropdownItemIcon>
<LifeBuoy />
</AnimatedDropdownItemIcon>
<AnimatedDropdownItemText>Support</AnimatedDropdownItemText>
</AnimatedDropdownItem>
</AnimatedDropdownContent>
</AnimatedDropdown>
</div>
</div>
);
}
Source code is locked
Get access to install premium components and view the full source.
Open dashboardInstall
$ bunx --bun shadcn add @beui-pro/animated-dropdown