Dropdown menu
BetaUna lista de acciones detrás de un botón.
registry/ds/menu.tsximport { Button } from "@/registry/ds/button";
import { ArrowUpRight, Close, DotsVertical, Plus } from "@/registry/ds/icons";
import { Menu, MenuGroup, MenuItem, MenuSeparator } from "@/registry/ds/menu";
export default function MenuBasic() {
return (
<Menu trigger={<Button variant="stroke" iconOnly={<DotsVertical />} aria-label="Más opciones" />} align="end">
<MenuGroup label="Materia">
<MenuItem icon={<Plus />} shortcut="⌘N">Agregar a mi plan</MenuItem>
<MenuItem icon={<ArrowUpRight />} href="#">Ver programa</MenuItem>
<MenuItem disabled>Compartir</MenuItem>
</MenuGroup>
<MenuSeparator />
<MenuItem icon={<Close />} destructive>Dar de baja</MenuItem>
</Menu>
);
}Cuándo usarlo
Para acciones sobre algo (editar, duplicar, eliminar) cuando no entran como botones. Para elegir un valor de un formulario, Select.
- 3 a 8 items. Menos, ponelos como botones; más, agrupá.
- Verbo + objeto, en infinitivo: "Ver programa", "Dar de baja".
- La acción destructiva va última, separada y en rojo.
- Un item deshabilitado se ve pero no se activa; explicá por qué en otro lado.
- Items con casilla (
MenuCheckboxItem) para alternar opciones que siguen visibles, como columnas de una tabla:
"use client";
import { useState } from "react";
import { Button } from "@/registry/ds/button";
import { ChevronDown } from "@/registry/ds/icons";
import { Menu, MenuCheckboxItem, MenuGroup } from "@/registry/ds/menu";
export default function MenuCheckbox() {
const [cols, setCols] = useState({ codigo: true, docente: true, cupo: false });
return (
<Menu trigger={<Button variant="tonal" size="sm" iconRight={<ChevronDown />}>Columnas</Button>}>
<MenuGroup label="Mostrar">
{(["codigo", "docente", "cupo"] as const).map((k) => (
<MenuCheckboxItem key={k} checked={cols[k]} onCheckedChange={(v) => setCols((c) => ({ ...c, [k]: v }))} closeOnClick={false}>
{{ codigo: "Código", docente: "Docente", cupo: "Cupo" }[k]}
</MenuCheckboxItem>
))}
</MenuGroup>
</Menu>
);
}| Parte | Medida |
|---|---|
| Popup | ancho mín. 192 · padding 4 · radius-md 8 · a 4 del disparador |
| Item | alto mín. 36 · px 10 · gap 10 · radius-sm 6 · Text sm |
| Icono | 16 |
| Label de grupo | Text xs / Medium |
| Parte | Propiedad | Token |
|---|---|---|
| Popup | Fondo · borde · sombra | bg/elevated |
| Item | Texto | text/default |
| Item | Icono | icon/muted |
| Item resaltado | Fondo | bg/surface |
| Destructivo | Texto | danger/text |
| Destructivo · resaltado | Fondo | danger/faint |
| Deshabilitado | Texto | text/disabled |
| Label de grupo · atajo | Color | text/subtle |
| Separador | Borde | border/subtle |
| Check | Color | primary/accent |
Instalación
npx shadcn@latest add https://polen.cdc.cool/r/menu.jsonSobre Base UI Menu.
Playground
Configurá el componente y copiá el snippet: se genera del mismo estado que renderiza el preview.
Disparador
Lado
Alineación
<Menu trigger={<Button variant="stroke" iconOnly={<DotsVertical />} aria-label="Más opciones" />}>
<MenuGroup label="Materia">
<MenuItem icon={<Plus />} onClick={add}>Agregar a mi plan</MenuItem>
<MenuItem icon={<ArrowUpRight />} href="/programa">Ver programa</MenuItem>
<MenuItem disabled>Compartir</MenuItem>
</MenuGroup>
<MenuSeparator />
<MenuItem icon={<Close />} destructive onClick={remove}>Dar de baja</MenuItem>
</Menu>| Prop | Tipo | Default | Descripción |
|---|---|---|---|
Menu · trigger | ReactElement | — | Requerido. Suele ser un Button icon-only con aria-label. |
Menu · side · align | string | "bottom" · "start" | Posición. |
MenuItem · icon | ReactNode | — | 16 px, a la izquierda. |
MenuItem · destructive | boolean | — | Rojo. Va último y separado. |
MenuItem · shortcut | string | — | Atajo informativo, a la derecha. |
MenuItem · href | string | — | Lo vuelve un link. |
MenuItem · onClick · disabled | — | — | Como un botón. |
MenuCheckboxItem · checked · onCheckedChange | boolean · (v) => void | — | Item con casilla. closeOnClick={false} para marcar varios. |
MenuGroup · label | ReactNode | — | Agrupa con título. |
| Tecla | Qué hace |
|---|---|
| EnterEspacio↓ | Abre el menú y enfoca el primer item. |
| ↑↓ | Mueve el resaltado. |
| A–Z | Salta al item que empieza con esa letra. |
| Enter | Activa el item. |
| Esc | Cierra y devuelve el foco al disparador. |
role="menu" / menuitem / menuitemcheckbox con aria-checked. El
disparador icon-only necesita aria-label ("Más opciones").