Context menu
Un 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.
Last action: Nothing yet
pnpm dlx shadcn@latest add https://hextaui.com/r/context-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/context-menu.tsx Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
Lista de archivos
Dale a cada fila su propio menú. La fila abierta mantiene un resaltado, y un elemento destructivo pasa el relevo a un alert dialog para confirmar.
Controlado
Pasa open y onOpenChange para controlar el estado. El segundo argumento indica por qué cambió, como trigger-press, outside-press o escape-key. Los elementos con closeOnClick={false} lo mantienen abierto.
Deshabilitado
Un <ContextMenu /> deshabilitado devuelve el área al menú propio del navegador. Los elementos deshabilitados siguen visibles pero el teclado los omite.
Feedback al mantener pulsado
En pantallas táctiles el menú se abre tras una pulsación larga. Mientras se mantiene el dedo, el área se encoge ligeramente para que se note que la pulsación se registró. Mover el dedo la cancela. Define holdFeedback={false} para desactivarlo.
Contenido largo
Las etiquetas largas se ajustan dentro de un ancho máximo de 20rem, y los menús altos se desplazan dentro del espacio que queda en el viewport.
Submenús anidados
Los submenús se abren al pasar el cursor o con las teclas de flecha, a cualquier profundidad. El trigger de un submenú deshabilitado nunca se abre.
Dentro de una hoja
El menú se apila sobre otras superposiciones, y Escape cierra solo el menú, no el sheet que hay detrás.
Renderizar como otro elemento
Usa render para convertir el trigger en cualquier elemento, como una figure, o para convertir un elemento en un enlace.
De derecha a izquierda
El menú lee la dirección del trigger, así que los submenús se abren hacia la izquierda y las teclas de flecha se invierten.
| Key | Acción |
|---|---|
| ↓ | 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. En un submenú, solo se cierra ese submenú. |
| A–Z | Resalta el siguiente elemento que empiece por esa letra. |
- Un menú contextual es un atajo. Haz que cada acción que contiene sea accesible también de otra forma, como un botón visible o un menú desplegable, ya que muchas personas nunca hacen clic derecho ni una pulsación larga.
- Los navegadores también disparan el evento de menú contextual con Shift F10 y la tecla Menu en un elemento con foco, así que un elemento enfocable dentro del trigger permite abrirlo a los usuarios de teclado.
- Los atajos de
<ContextMenuShortcut />son solo etiquetas. Enlaza las teclas tú mismo. - Con movimiento reducido, se omiten el feedback al mantener pulsado y el parpadeo del elemento, y el menú solo se desvanece.
Construido sobre el context menu de Base UI. Cada parte acepta las props de la primitiva que envuelve, y un className en forma de función que recibe el estado de la parte.
| Prop | Tipo | Predeterminado |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
onOpenChangedetails.reason indica qué causó el cambio. | (open: boolean, details) => void | – |
onOpenChangeCompleteSe ejecuta cuando termina la animación de apertura o cierre. | (open: boolean) => void | – |
disabledMuestra en su lugar el menú nativo del navegador. | boolean | false |
loopFocusDa la vuelta a la navegación con teclas de flecha en los extremos. | boolean | true |
highlightItemOnHover | boolean | true |
actionsRefCierra el menú de forma imperativa. | RefObject<{ close, unmount }> | – |
| Prop | Tipo | Predeterminado |
|---|---|---|
holdFeedbackEncoge ligeramente el área mientras se mantiene una pulsación larga en pantallas táctiles. | boolean | true |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="context-menu-trigger" | Apunta al trigger en CSS. |
data-popup-open | Presente mientras su menú está abierto. |
data-holding | Presente mientras se mantiene una pulsación larga. |
data-pressed | Presente mientras el trigger está pulsado. |
| Prop | Tipo | Predeterminado |
|---|---|---|
sideLado preferido, relativo al puntero. | "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" | "bottom" |
align | "start" | "center" | "end" | "start" |
sideOffset | number | 0 |
alignOffset | number | 0 |
collisionPaddingEspacio que se mantiene entre el menú y los bordes del viewport. | number | { top, right, bottom, left } | – |
collisionAvoidanceCómo se voltea o desplaza el menú cuando se desbordaría. | CollisionAvoidance | – |
anchorPosiciona respecto a algo distinto del puntero. | Element | VirtualElement | RefObject | – |
finalFocusAdónde va el foco después de cerrarse el menú. | boolean | RefObject | (closeType) => HTMLElement | boolean | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="context-menu-content" | El popup del menú. |
data-open | Presente mientras 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 colocó tras las colisiones. |
data-chosen | Presente tras hacer clic en un elemento. El fundido de salida espera al parpadeo. |
--transform-origin | El punto desde el que crece la animación de escala. |
--available-height | Espacio que queda en el viewport. Limita la altura del menú. |
| Prop | Tipo | Predeterminado |
|---|---|---|
variant | "default" | "destructive" | "default" |
insetSangra la etiqueta para alinearla con los elementos checkbox. | boolean | false |
onClickSe ejecuta al hacer clic, con Enter o con Space. El menú se cierra tras un breve parpadeo. | (event) => void | – |
closeOnClick | boolean | true |
disabled | boolean | false |
labelTexto usado para la búsqueda por escritura cuando los hijos no son texto simple. | string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="context-menu-item" | Apunta a los elementos en CSS. |
data-variant | La variante actual. |
data-highlighted | Presente en el elemento bajo el puntero o el foco del teclado. |
data-disabled | Presente cuando el elemento está deshabilitado. |
data-inset | Presente cuando se define inset. |
data-chosen | Presente en el elemento clicado mientras parpadea. |
| Prop | Tipo | Predeterminado |
|---|---|---|
checked | boolean | – |
defaultChecked | boolean | false |
onCheckedChange | (checked: boolean, details) => void | – |
closeOnClick | boolean | false |
inset | boolean | false |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="context-menu-checkbox-item" | Selecciona los elementos checkbox en CSS. |
data-checked | Presente cuando está marcado. |
data-unchecked | Presente cuando está desmarcado. |
data-highlighted | Presente en el elemento bajo el puntero o el foco del teclado. |
data-disabled | Presente cuando el elemento está deshabilitado. |
data-inset | Presente cuando se define inset. |
data-chosen | Presente en el elemento clicado mientras parpadea. |
| Prop | Tipo | Predeterminado |
|---|---|---|
value | any | – |
defaultValue | any | – |
onValueChange | (value: any, details) => void | – |
disabled | boolean | false |
| Prop | Tipo | Predeterminado |
|---|---|---|
value | any | – |
closeOnClick | boolean | false |
inset | boolean | false |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="context-menu-radio-item" | Selecciona los elementos radio en CSS. |
data-checked | Presente cuando está seleccionado. |
data-highlighted | Presente en el elemento bajo el puntero o el foco del teclado. |
data-disabled | Presente cuando el elemento está deshabilitado. |
data-inset | Presente cuando se define inset. |
data-chosen | Presente en el elemento clicado mientras parpadea. |
| Prop | Tipo | Predeterminado |
|---|---|---|
inset | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
Dentro de <ContextMenuGroup /> o <ContextMenuRadioGroup /> etiqueta el grupo para las tecnologías de asistencia. En otros sitios es un encabezado simple.
| Prop | Tipo | Predeterminado |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
onOpenChange | (open: boolean, details) => void | – |
disabled | boolean | false |
closeParentOnEscCierra todo el menú con Escape, no solo este submenú. | boolean | false |
| Prop | Tipo | Predeterminado |
|---|---|---|
inset | boolean | false |
openOnHover | boolean | true |
delayMilisegundos de hover antes de que se abra el submenú. | number | 100 |
closeDelay | number | 0 |
disabled | boolean | false |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="context-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. |
data-disabled | Presente cuando está deshabilitado. |
| Prop | Tipo | Predeterminado |
|---|---|---|
sideSe abre hacia el final en línea por defecto. | "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" | – |
align | "start" | "center" | "end" | – |
sideOffset | number | 0 |
alignOffset | number | -4 |
collisionPaddingEspacio que se mantiene entre el menú y los bordes del viewport. | number | { top, right, bottom, left } | – |
collisionAvoidanceCómo se voltea o desplaza el menú cuando se desbordaría. | CollisionAvoidance | – |
anchorPosiciona respecto a algo distinto del puntero. | Element | VirtualElement | RefObject | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="context-menu-sub-content" | El popup del submenú. Acepta los mismos atributos de estado que el menú. |
| Prop | Tipo | Predeterminado |
|---|---|---|
dirMantiene en orden atajos como ⇧⌘S dentro de menús de derecha a izquierda. | "ltr" | "rtl" | "ltr" |
| Atributo | Descripción |
|---|---|
data-slot="context-menu-shortcut" | La etiqueta del atajo. |
<ContextMenuGroup /> agrupa elementos relacionados bajo una etiqueta. <ContextMenuSeparator /> dibuja un divisor. Ambos aceptan render y className, y llevan context-menu-group y context-menu-separator como su data-slot.
- 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.
- 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.
- Dropdown menuUn menú de acciones y opciones tras un botón, con grupos, submenús, elementos de casilla y de radio, y atajos.
- 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 Context menu.