Hover card
Una tarjeta de vista previa que se abre al pasar el cursor o enfocar un enlace, para contenido que los usuarios videntes pueden ojear.
pnpm dlx shadcn@latest add https://hextaui.com/r/hover-card.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 cnCopia y pega el siguiente código en tu proyecto.
components/ui/hover-card.tsx lib/motion.ts Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
Una hover card es una vista previa, no un menú ni un diálogo. El trigger sigue siendo un enlace normal, así que todo lo que hay en la tarjeta también debe estar en la página a la que enlaza.
Lado
Define side y align en <HoverCardContent />. Los lados lógicos como inline-end siguen la dirección de lectura, y la tarjeta se voltea o desplaza cuando saldría de la pantalla.
Retraso
delay y closeDelay en el trigger definen cuánto debe reposar el puntero antes de que se abra la tarjeta y cuánto permanece tras salir. El valor por defecto de 600ms evita que las tarjetas se abran de golpe cuando el puntero cruza una página.
Enlace en línea
Usa render para convertir el trigger en cualquier enlace, incluido uno dentro de una frase. Cuando un enlace se parte en dos líneas, la tarjeta se ancla a la línea sobre la que pasaste el cursor.
Contenido interactivo
Mueve el puntero del enlace a la tarjeta y esta permanece abierta, así que se puede hacer clic en los enlaces y botones de su interior. El camino entre ambos es tolerante, de modo que un movimiento diagonal no la cierra.
Tarjeta compartida
Una tarjeta sirve a muchos enlaces. Crea un handle con createHoverCardHandle, dale a cada trigger un payload y léelo en la tarjeta. Al moverte entre nombres, la tarjeta se desliza hasta el nuevo enlace en lugar de cerrarse y reabrirse. El contenido anterior sale deslizándose en la dirección en que te moviste, el nuevo entra y la altura se ajusta suavemente entre ambos.
Flecha
arrow añade una flecha que se une al borde de la tarjeta sin costura. El desplazamiento lateral crece para dejarle sitio, y sigue a la tarjeta cuando se voltea.
Contenido en carga
Empieza a obtener los datos en onOpenChange y muestra un skeleton hasta que lleguen. Cuando el contenido cambia, la tarjeta se ajusta suavemente a su nueva altura en lugar de saltar.
Controlado
Pasa open y onOpenChange. El segundo argumento indica por qué cambió, como trigger-hover, trigger-focus o escape-key.
Contenido largo
El texto sin espacios se ajusta dentro de la tarjeta, y una tarjeta más alta que el espacio junto al trigger se desplaza en lugar de salirse de la pantalla.
De derecha a izquierda
La tarjeta lee la dirección del trigger, así que los lados lógicos y la alineación se invierten y la animación de escala crece desde la esquina correcta.
| Key | Acción |
|---|---|
| Tab | Dar foco al trigger abre la tarjeta tras el mismo retraso que al pasar el cursor. Mover el foco a otro lugar la cierra. |
| Enter | Sigue el enlace, como cualquier otro enlace. |
| Esc | Cierra la tarjeta. |
- La tarjeta es un extra visual para usuarios videntes de ratón y teclado. Los lectores de pantalla solo oyen el enlace, así que no se les obliga a pasar por una vista previa en cada enlace.
- No se abre nada en pantallas táctiles, donde no hay hover. Un toque sigue el enlace, y por eso el destino debe contener la misma información.
- El foco nunca entra en la tarjeta. Si necesita controles que deban ser accesibles con el teclado, usa un popover en su lugar.
- Con movimiento reducido, la tarjeta se desvanece sin escalar, y una tarjeta compartida salta entre enlaces en lugar de deslizarse.
Construido sobre la preview card de Base UI. Cada parte acepta las props de la primitiva que envuelve.
| Prop | Tipo | Predeterminado |
|---|---|---|
open | boolean | – |
defaultOpen | boolean | false |
onOpenChangedetails.reason es trigger-hover, trigger-focus, trigger-press, outside-press, escape-key, imperative-action o none. | (open: boolean, details) => void | – |
onOpenChangeCompleteSe llama cuando termina la animación de apertura o cierre. | (open: boolean) => void | – |
handleConecta triggers renderizados fuera de la raíz. | HoverCardHandle<Payload> | – |
childrenUsa la forma de función para leer el payload del trigger que abrió la tarjeta. | ReactNode | ({ payload }) => ReactNode | – |
actionsRef | RefObject<{ close, unmount }> | – |
| Prop | Tipo | Predeterminado |
|---|---|---|
href | string | – |
delayMilisegundos antes de que pasar el cursor o recibir foco abra la tarjeta. | number | 600 |
closeDelayMilisegundos que la tarjeta permanece abierta tras salir. | number | 300 |
handle | HoverCardHandle<Payload> | – |
payloadSe pasa a la tarjeta cuando este trigger la abre. | Payload | – |
renderRenderiza tu propio enlace, como <Button variant="link" /> o un enlace del router. | ReactElement | (props, state) => ReactElement | <a> |
| Atributo | Descripción |
|---|---|
data-slot="hover-card-trigger" | Apunta al trigger en CSS. |
data-popup-open | Presente mientras está abierta la tarjeta de este trigger. |
| Prop | Tipo | Predeterminado |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" |
align | "start" | "center" | "end" | "center" |
arrowMuestra una flecha que apunta al trigger. | boolean | false |
sideOffset | number | OffsetFunction | 6, or 10 with arrow |
alignOffset | number | OffsetFunction | 0 |
collisionPaddingEspacio que se mantiene entre la tarjeta y el borde del viewport. | number | Rect | 8 |
collisionAvoidanceSi la tarjeta se voltea, se desplaza o no hace nada en una colisión. | CollisionAvoidance | – |
sticky | boolean | false |
anchorPosiciona respecto a algo distinto del trigger. | Element | RefObject | VirtualElement | – |
positionMethod | "absolute" | "fixed" | "absolute" |
disableAnchorTracking | boolean | false |
portalPropsProps para el portal, como container. | HoverCardPortalProps | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="hover-card-content" | Apunta a la tarjeta en CSS. |
data-open | Presente mientras la tarjeta está abierta. |
data-starting-style | Presente mientras la tarjeta se anima al abrirse. |
data-ending-style | Presente mientras la tarjeta se anima al cerrarse. |
data-instant | focus cuando el foco del teclado abrió la tarjeta, dismiss cuando Escape o una pulsación exterior la cerró. La animación de salida se omite mientras está definido. |
data-side | El lado en el que se asentó la tarjeta tras las colisiones. |
data-align | La alineación en la que se asentó. |
--transform-origin | Desde dónde crece la animación de escala, junto al trigger. |
--available-width | Espacio que queda junto al trigger. La tarjeta nunca crece más allá. |
--available-height | Espacio que queda arriba o abajo. El contenido más alto se desplaza. |
| Atributo del posicionador | Descripción |
|---|---|
data-slot="hover-card-positioner" | El elemento que se mueve. Se desliza cuando una tarjeta compartida cambia de enlace. |
data-anchor-hidden | Presente cuando el trigger sale de la vista al desplazarse. |
| Partes internas | Descripción |
|---|---|
data-slot="hover-card-viewport" | Envuelve el contenido. Lleva data-activation-direction mientras una tarjeta compartida cambia de enlace. |
data-slot="hover-card-body" | Tu contenido. Su altura se ajusta suavemente cuando cambia. |
data-slot="hover-card-arrow" | La flecha, con data-side para su borde. |
--popup-height | Se define en la tarjeta mientras cambia de tamaño entre enlaces. |
| Prop | Tipo | Predeterminado |
|---|---|---|
container | HTMLElement | ShadowRoot | RefObject | null | document.body |
keepMounted | boolean | false |
Devuelve un handle para triggers separados. Sus métodos open(triggerId) y close() controlan la tarjeta desde manejadores de eventos, y isOpen lee su estado. Pasa un argumento de tipo para tipar el payload.
- MotionLas curvas de easing, duraciones y la comprobación de movimiento reducido con las que se anima cada componente, además de hooks para transformaciones de tamaño y resaltados deslizantes.
- 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.
Usado en bloques
Bloques que se construyen sobre Hover card.
- 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.
- ThinkingMuestra lo que hace un modelo mientras trabaja. Una esfera de shader y una etiqueta en vivo que sigue cada paso, un rastro colapsable de búsquedas, chips de fuentes y razonamiento, y luego una respuesta con citas justo al lado de las afirmaciones que respaldan.