default.tsx
1'use client';23import {4 KeyboardIcon,5 Logout02Icon,6 Notification03Icon,7 Settings01Icon,8 Shield02Icon,9 UserIcon,10} from '@hugeicons/core-free-icons';11import { HugeiconsIcon } from '@hugeicons/react';12import { Button } from '@/components/ui/button';13import { DropdownMenu } from '@/components/ui/dropdown-menu';1415const menuGroups = [16 {17 label: 'Account',18 items: [19 { icon: UserIcon, label: 'Profile' },20 { icon: Notification03Icon, label: 'Notifications' },21 { icon: Settings01Icon, label: 'Settings' },22 ],23 },24 {25 label: 'Security',26 items: [27 { icon: Shield02Icon, label: 'Privacy & Security' },28 { icon: KeyboardIcon, label: 'Keyboard shortcuts' },29 ],30 },31];3233const actionItems = [{ icon: Logout02Icon, label: 'Sign out', destructive: true }];3435export function Default() {36 return (37 <DropdownMenu>38 <DropdownMenu.Trigger asChild>39 <Button variant="outline">Account</Button>40 </DropdownMenu.Trigger>41 <DropdownMenu.Content className="w-56" align="start">42 {menuGroups.map((group, groupIdx) => (43 <div key={groupIdx}>44 <DropdownMenu.Label>{group.label}</DropdownMenu.Label>45 {group.items.map((item, itemIdx) => (46 <DropdownMenu.Item key={itemIdx}>47 <HugeiconsIcon icon={item.icon} className="mr-2 size-4" />48 {item.label}49 </DropdownMenu.Item>50 ))}51 <DropdownMenu.Separator />52 </div>53 ))}54 {actionItems.map((item, idx) => (55 <DropdownMenu.Item56 key={idx}57 className={item.destructive ? 'text-destructive focus:text-destructive' : ''}58 >59 <HugeiconsIcon icon={item.icon} className="mr-2 size-4" />60 {item.label}61 </DropdownMenu.Item>62 ))}63 </DropdownMenu.Content>64 </DropdownMenu>65 );66}
Instalación
pnpm dlx nachui add dropdown-menuAnatomía
1import { DropdownMenu } from '@/components/ui/dropdown-menu';
1<DropdownMenu>2 <DropdownMenu.Trigger asChild>3 <Button variant="outline">Abrir Menú</Button>4 </DropdownMenu.Trigger>5 <DropdownMenu.Content>6 <DropdownMenu.Label>Mi Cuenta</DropdownMenu.Label>7 <DropdownMenu.Item>Perfil</DropdownMenu.Item>8 <DropdownMenu.Item>Configuración</DropdownMenu.Item>9 <DropdownMenu.Separator />10 <DropdownMenu.Item variant="destructive">Cerrar Sesión</DropdownMenu.Item>11 </DropdownMenu.Content>12</DropdownMenu>
Variantes
Casillas de verificación (Checkboxes)
checkboxes.tsx
1'use client';23import { Tick02Icon } from '@hugeicons/core-free-icons';4import { HugeiconsIcon } from '@hugeicons/react';5import * as React from 'react';6import { Button } from '@/components/ui/button';7import { DropdownMenu } from '@/components/ui/dropdown-menu';89const ITEMS = [10 { id: 'status-bar', label: 'Status Bar' },11 { id: 'activity-bar', label: 'Activity Bar' },12 { id: 'panel', label: 'Panel' },13] as const;1415const INITIAL_STATE: Record<string, boolean> = {16 'status-bar': true,17 'activity-bar': false,18 panel: false,19};2021export function Checkboxes() {22 const [checked, setChecked] = React.useState<Record<string, boolean>>(INITIAL_STATE);2324 const toggle = (id: string) => setChecked((prev) => ({ ...prev, [id]: !prev[id] }));2526 return (27 <DropdownMenu>28 <DropdownMenu.Trigger asChild>29 <Button variant="outline">View Options</Button>30 </DropdownMenu.Trigger>31 <DropdownMenu.Content className="w-56" align="start">32 <DropdownMenu.Label>Appearance</DropdownMenu.Label>33 <DropdownMenu.Separator />34 {ITEMS.map(({ id, label }) => (35 <DropdownMenu.Item key={id} onClick={() => toggle(id)}>36 <span className="flex w-6 items-center justify-center">37 {checked[id] && <HugeiconsIcon icon={Tick02Icon} size={16} />}38 </span>39 {label}40 </DropdownMenu.Item>41 ))}42 </DropdownMenu.Content>43 </DropdownMenu>44 );45}
Grupo de radio (Radio Group)
radio-group.tsx
1'use client';23import * as React from 'react';4import { Button } from '@/components/ui/button';5import { DropdownMenu } from '@/components/ui/dropdown-menu';67export function RadioGroup() {8 const [position, setPosition] = React.useState('bottom');910 return (11 <DropdownMenu>12 <DropdownMenu.Trigger asChild>13 <Button variant="outline">Panel Position</Button>14 </DropdownMenu.Trigger>15 <DropdownMenu.Content className="w-56" align="start">16 <DropdownMenu.Label>Panel Position</DropdownMenu.Label>17 <DropdownMenu.Separator />18 {['Top', 'Bottom', 'Right', 'Left'].map((pos) => {19 const value = pos.toLowerCase();20 const isSelected = position === value;21 return (22 <DropdownMenu.Item key={value} onClick={() => setPosition(value)}>23 <span className="flex w-6 items-center justify-center">24 {isSelected && <div className="bg-foreground size-2 rounded-full" />}25 </span>26 {pos}27 </DropdownMenu.Item>28 );29 })}30 </DropdownMenu.Content>31 </DropdownMenu>32 );33}
Referencia de API
DropdownMenu
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
defaultOpen | boolean | false | Estado abierto inicial |
onOpenChange | (open: boolean) => void | - | Callback cuando cambia el estado |
className | string | - | Clases CSS adicionales |
DropdownMenu.Trigger
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
asChild | boolean | false | Renderizar como elemento hijo |
className | string | - | Clases CSS adicionales |
DropdownMenu.Content
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
align | 'start' | 'center' | 'end' | 'start' | Alineación horizontal |
sideOffset | number | 6 | Distancia del activador |
className | string | - | Clases CSS adicionales |
DropdownMenu.Item
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
disabled | boolean | false | Deshabilitar el elemento |
variant | 'default' | 'destructive' | 'default' | Estilo visual |
onSelect | () => void | - | Callback cuando se selecciona |
className | string | - | Clases CSS adicionales |
DropdownMenu.Label
| Prop | Tipo | Por defecto | Descripción |
|---|---|---|---|
children | ReactNode | - | Texto de la etiqueta |
DropdownMenu.Separator
Separador visual entre elementos del menú.
Sin props - renderiza una línea horizontal.
¿Encontraste algo que mejorar?
¿Notaste un error, tipografía o detalle faltante en esta página? Ayúdanos a mejorar la documentación abriendo un issue en GitHub.