Dropdown menu
Un menú de acciones y opciones tras un botón, con grupos, submenús, elementos de casilla y de radio, y atajos.
pnpm dlx shadcn@latest add https://hextaui.com/r/dropdown-menu.jsonAñade el componente, los tokens del tema de HextaUI y los componentes de HextaUI de los que depende.
Añade los tokens del tema a tu CSS global, si aún no lo has hecho.
Instala las dependencias.
pnpm add @base-ui/react @tabler/icons-react class-variance-authority cnCopia y pega el siguiente código en tu proyecto.
components/ui/dropdown-menu.tsx Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
Área segura
Al moverse en diagonal desde el trigger de un submenú hacia su submenú se cruzan triggers hermanos. El área segura mantiene el submenú abierto mientras el puntero se dirige hacia él. Activa showSafeArea para verlo en vivo: el punto se vuelve verde dentro del área y rojo donde el submenú cambiaría.
Casillas de verificación
<DropdownMenuCheckboxItem /> alterna un ajuste y mantiene el menú abierto, así que se pueden cambiar varios seguidos. La marca se dibuja al entrar y al salir en lugar de aparecer de golpe.
Radio group
Envuelve <DropdownMenuRadioItem /> en un <DropdownMenuRadioGroup /> para elegir una opción. Una etiqueta dentro del grupo lo nombra para los lectores de pantalla.
Marca a la derecha
Define indicator="end" en los elementos checkbox y radio para mostrar la marca después de la etiqueta en lugar de sangrarla, lo que encaja con selectores que llevan una descripción bajo cada opción.
Tipo select
El menú nunca es más estrecho que su trigger. Define closeOnClick en los elementos radio cuando elegir uno deba cerrar también el menú.
Acciones de fila
Un menú sirve a todas las filas. Crea un handle con createDropdownMenuHandle, pásalo a cada trigger con un payload y lee el payload en el menú. Delete pasa el relevo a un alert dialog.
Controlado
Pasa open y onOpenChange. El segundo argumento indica por qué cambió el menú, como una pulsación del trigger, de un elemento o Escape. Los elementos con closeOnClick={false} lo mantienen abierto.
Abrir al pasar el cursor
openOnHover en el trigger abre el menú tras delay y lo cierra tras closeDelay. El clic y el teclado siguen funcionando, así que los usuarios de táctil y teclado no quedan excluidos.
Deshabilitado
Un trigger deshabilitado nunca se abre. Los elementos deshabilitados siguen visibles y las teclas de flecha los omiten.
Contenido largo
Las etiquetas se ajustan en lugar de estirar el menú más allá de 20rem, las cadenas sin espacios se cortan en cualquier punto y los atajos permanecen en la primera línea.
Desplazamiento
Cuando no hay espacio para todos los elementos, el menú se desplaza dentro del viewport y el elemento resaltado se desplaza hasta quedar visible.
Dentro de una hoja
El menú se apila sobre el sheet. Escape cierra primero el menú y luego el sheet.
De derecha a izquierda
El menú, el chevron del submenú y el lado del submenú siguen la dirección del trigger. Los atajos conservan su orden de izquierda a derecha.
| Key | Acción |
|---|---|
| EnterSpace↓ | En el trigger, abre el menú y resalta el primer elemento. |
| ↓ | Resalta el elemento siguiente, volviendo al principio al llegar al final. |
| ↑ | Resalta el elemento anterior, volviendo al final al llegar al principio. |
| Home | Resalta el primer elemento. |
| End | Resalta el último elemento. |
| EnterSpace | Ejecuta el elemento resaltado. Los elementos checkbox y radio alternan y mantienen el menú abierto. |
| → | Abre el submenú resaltado y entra en él. ← en diseños de derecha a izquierda. |
| ← | Cierra el submenú actual y vuelve a su trigger. → en diseños de derecha a izquierda. |
| Esc | Cierra el menú actual y devuelve el foco a su trigger. En un submenú, solo se cierra ese submenú. |
| A–Z | Resalta el siguiente elemento que empiece por esa letra. |
- El trigger se anuncia como un botón de menú, y el foco vuelve a él cuando el menú se cierra.
- Dale a los triggers solo con icono un
aria-label, como hace el ejemplo de acciones de fila. <DropdownMenuShortcut />es solo una etiqueta visual. Enlaza las teclas tú mismo.- Con movimiento reducido, el menú se desvanece sin escalar y se omite el parpadeo del elemento.
Construido sobre el menu de Base UI. Cada parte acepta las props de la primitiva que envuelve.
| Prop | Tipo | Predeterminado |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
showSafeAreaDibuja el área segura del submenú mientras el menú está abierto. Para depuración y demos. | boolean | false |
onOpenChangedetails.reason indica qué causó el cambio. | (open: boolean, details) => void | – |
modalBloquea el desplazamiento de la página y los clics exteriores mientras está abierto. | boolean | true |
loopFocusDa la vuelta a las teclas de flecha en cualquiera de los extremos. | boolean | true |
handleConecta triggers separados con este menú. | DropdownMenuHandle<Payload> | – |
childrenUsa la forma de función para leer el payload del trigger que abrió el menú. | ReactNode | ({ payload }) => ReactNode | – |
disabled | boolean | false |
| Prop | Tipo | Predeterminado |
|---|---|---|
openOnHover | boolean | false |
delayMilisegundos antes de que pasar el cursor abra el menú. | number | 100 |
closeDelayMilisegundos antes de que se cierre un menú abierto al pasar el cursor. | number | 0 |
handle | DropdownMenuHandle<Payload> | – |
payloadSe pasa al menú cuando este trigger lo abre. | Payload | – |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <button> |
| Atributo | Descripción |
|---|---|
data-slot="dropdown-menu-trigger" | Apunta al trigger en CSS. |
data-popup-open | Presente mientras su menú está abierto. |
data-pressed | Presente mientras el trigger está pulsado. |
data-disabled | Presente cuando el trigger está deshabilitado. |
| Prop | Tipo | Predeterminado |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" |
align | "start" | "center" | "end" | "start" |
sideOffset | number | 4 |
alignOffset | number | 0 |
collisionPaddingEspacio que se mantiene entre el menú y el borde del viewport. | number | Rect | 8 |
anchorPosiciona respecto a otro elemento en lugar del trigger. | Element | RefObject | VirtualElement | – |
sticky | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="dropdown-menu-content" | Selecciona el menú en CSS. |
data-open | Presente mientras el menú está abierto. |
data-starting-style | Presente mientras el menú se anima al abrirse. |
data-ending-style | Presente mientras el menú se anima al cerrarse. |
data-side | El lado en el que se asentó el menú tras el manejo de colisiones. |
data-align | La alineación en la que se asentó. |
data-chosen | Presente tras hacer clic en un elemento, de modo que el menú espera al parpadeo de confirmación del elemento antes de cerrarse. |
--anchor-width | El ancho del trigger. El menú es al menos así de ancho. |
--available-height | Espacio que queda en el viewport. Los menús largos se desplazan dentro de él. |
--transform-origin | Desde dónde crece la animación de escala, junto al trigger. |
| Prop | Tipo | Predeterminado |
|---|---|---|
variant | "default" | "destructive" | "default" |
insetSangra el elemento para alinearlo con los elementos checkbox. | boolean | false |
closeOnClick | boolean | true |
onClick | (event) => void | – |
labelTexto usado para la búsqueda por escritura cuando los hijos no son texto simple. | string | – |
disabled | boolean | false |
renderRenderiza un enlace con render={<a href="…" />}. | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="dropdown-menu-item" | Apunta a los elementos en CSS. |
data-variant | La variante actual. |
data-highlighted | Presente mientras el elemento está resaltado por el puntero o el teclado. |
data-disabled | Presente cuando el elemento está deshabilitado. |
data-chosen | Presente en el elemento en que se acaba de hacer clic, mientras parpadea. |
data-inset | Presente cuando se define inset. |
| Prop | Tipo | Predeterminado |
|---|---|---|
checked | boolean | – |
defaultChecked | boolean | false |
onCheckedChange | (checked: boolean, details) => void | – |
closeOnClick | boolean | false |
inset | boolean | false |
indicator | "start" | "end" | "start" |
disabled | boolean | false |
| Atributo | Descripción |
|---|---|
data-slot="dropdown-menu-checkbox-item" | Selecciona los elementos checkbox en CSS. |
data-checked | Presente cuando está marcado. |
data-unchecked | Presente cuando no está marcado. |
data-highlighted | Presente mientras el elemento está resaltado por el puntero o el teclado. |
data-disabled | Presente cuando el elemento está deshabilitado. |
data-chosen | Presente en el elemento en que se acaba de hacer clic, mientras parpadea. |
data-inset | Presente cuando se define inset. |
| Prop | Tipo | Predeterminado |
|---|---|---|
value | Value | – |
defaultValue | Value | – |
onValueChange | (value: Value, details) => void | – |
disabled | boolean | false |
| Prop | Tipo | Predeterminado |
|---|---|---|
value | Value | – |
closeOnClick | boolean | false |
inset | boolean | false |
indicator | "start" | "end" | "start" |
disabled | boolean | false |
| Atributo | Descripción |
|---|---|
data-slot="dropdown-menu-radio-item" | Selecciona los elementos radio en CSS. |
data-checked | Presente en el elemento seleccionado. |
data-unchecked | Presente en los demás elementos. |
data-highlighted | Presente mientras el elemento está resaltado por el puntero o el teclado. |
data-disabled | Presente cuando el elemento está deshabilitado. |
data-chosen | Presente en el elemento en que se acaba de hacer clic, mientras parpadea. |
data-inset | Presente cuando se define inset. |
Agrupa elementos relacionados. Un <DropdownMenuLabel /> dentro de él se convierte en el nombre accesible del grupo.
| Prop | Tipo | Predeterminado |
|---|---|---|
inset | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
Un divisor entre grupos, anunciado como separador.
| Prop | Tipo | Predeterminado |
|---|---|---|
dirLos atajos conservan el orden de sus teclas en menús de derecha a izquierda. | "ltr" | "rtl" | "ltr" |
| Prop | Tipo | Predeterminado |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
onOpenChange | (open: boolean, details) => void | – |
closeParentOnEscCierra todo el menú, no solo este submenú, con Escape. | boolean | false |
| Prop | Tipo | Predeterminado |
|---|---|---|
inset | boolean | false |
disabled | boolean | false |
delayMilisegundos antes de que pasar el cursor abra el submenú. | number | 100 |
closeDelay | number | 0 |
| Atributo | Descripción |
|---|---|
data-slot="dropdown-menu-sub-trigger" | Selecciona los triggers de submenú en CSS. |
data-popup-open | Presente mientras su submenú está abierto. |
data-highlighted | Presente mientras está resaltado. |
| Prop | Tipo | Predeterminado |
|---|---|---|
sideOffset | number | 0 |
alignOffset | number | -4 |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="dropdown-menu-sub-content" | Selecciona los submenús en CSS. |
data-open | Presente mientras el menú está abierto. |
data-starting-style | Presente mientras el menú se anima al abrirse. |
data-ending-style | Presente mientras el menú se anima al cerrarse. |
data-side | El lado en el que se asentó el menú tras el manejo de colisiones. |
data-align | La alineación en la que se asentó. |
data-chosen | Presente tras hacer clic en un elemento, de modo que el menú espera al parpadeo de confirmación del elemento antes de cerrarse. |
--available-height | Espacio que queda en el viewport. Los menús largos se desplazan dentro de él. |
--transform-origin | Desde dónde crece la animación de escala, junto al trigger. |
- Alert dialogUn diálogo de confirmación para acciones destructivas o importantes que espera el trabajo asíncrono y se convierte en una hoja inferior en móviles.
- CommandUna lista de acciones con búsqueda, en línea o como paleta ⌘K, con páginas, atajos y coincidencias resaltadas.
- Context menuUn menú de acciones con clic derecho o pulsación larga, con submenús, elementos de casilla y de radio, y respuesta al mantener pulsado en pantallas táctiles.
- DialogUna ventana sobre la página para formularios y tareas concretas, con encabezado y pie fijados, anidamiento y una hoja inferior deslizable en móviles.
- DrawerUn panel que se desliza desde cualquier borde y sigue tu dedo, con puntos de anclaje, un tirador funcional y drawers anidados que se apilan.
- Hover cardUna tarjeta de vista previa que se abre al pasar el cursor o enfocar un enlace, para contenido que los usuarios videntes pueden ojear.
Usado en bloques
Bloques que se construyen sobre Dropdown menu.
- Prompt InputUn compositor de chat que empieza como una línea tranquila, crece hasta convertirse en una tarjeta mientras escribes y baja cuando empieza la conversación. Enter envía, de forma segura con entrada en japonés y chino. Pega, suelta o elige archivos con vistas previas, progreso y reintento. @ añade archivos y / ejecuta comandos desde un menú junto al cursor. Un selector de modelo con teclas numéricas, un control deslizante de esfuerzo que cobra vida en Max, un anillo de contexto, dictado con forma de onda en vivo, chips de herramientas, una cola para los mensajes escritos mientras se transmite una respuesta y borradores que sobreviven a una recarga.
- API keysLa página de claves de API de un producto de IA, como las consolas de OpenAI y Anthropic. Crea claves con permisos acotados y caducidad, ve el secreto una sola vez con una copia que lo confirma, revoca con deshacer, renombra en el sitio, rota con un periodo de gracia y consulta el uso por clave.
- ArtifactEl panel junto a un chat de IA que muestra lo que creó el modelo. Páginas web, SVG, documentos y código llegan en streaming y luego pasan a una vista previa en sandbox, con versiones que puedes comparar y restaurar, una división redimensionable y una hoja inferior en móviles.
- Chat SidebarLa barra lateral de una app de chat. Logo, búsqueda y Nuevo chat arriba, tus propios enlaces debajo, chats fijados, proyectos que se expanden para mostrar sus chats, recientes agrupados por día y filas con menús al pasar el cursor y con clic derecho, renombrado en línea, eliminación con deshacer y estados de respuesta en vivo.