Drawer
Un panel que se desliza desde cualquier borde y sigue tu dedo, con puntos de anclaje, un tirador funcional y drawers anidados que se apilan.
pnpm dlx shadcn@latest add https://hextaui.com/r/drawer.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 cnCopia y pega el siguiente código en tu proyecto.
components/ui/drawer.tsx components/ui/sheet.tsx components/ui/button.tsx Actualiza las rutas de importación para que coincidan con la configuración de tu proyecto.
Direcciones
Define swipeDirection en <Drawer /> para elegir el borde. El drawer se abre desde ese borde y se desliza de vuelta hacia él. Los drawers superior e inferior muestran un tirador por defecto.
Puntos de ajuste
Pasa snapPoints para que un drawer inferior repose en alturas predefinidas. Los números de 0 a 1 son fracciones del viewport, los números mayores son píxeles y las cadenas aceptan px o rem. La parte visible siempre se ajusta a su contenido, así que nada queda oculto bajo la pantalla.
Contenido desplazable
<DrawerBody /> se desplaza por sí solo, así que el encabezado y el pie permanecen en su sitio. El deslizamiento solo empieza cuando el cuerpo vuelve a estar desplazado hasta arriba.
Formularios y el teclado
Envuelve <DrawerContent /> en <DrawerVirtualKeyboardProvider /> cuando un drawer inferior contenga campos de texto. En teléfonos, el campo con foco se desplaza hasta quedar visible sobre el teclado de software en lugar de esconderse tras él. Mantén los campos en <DrawerBody /> para que el encabezado y el pie permanezcan fijos.
Anidado
Un drawer abierto desde un drawer en el mismo borde se apila encima. Los de detrás se encogen, asoman por encima y siguen tu dedo mientras deslizas el de arriba para quitarlo.
Confirmar desde un drawer
Los dialogs, alert dialogs, sheets y drawers de otro borde se superponen en lugar de apilarse. El drawer retrocede y un fondo más claro lo cubre.
Responsive
Cambia swipeDirection con una media query para mostrar un panel lateral en escritorio y una hoja inferior en teléfonos.
No modal
Con modal={false} no hay fondo, la página sigue desplazándose y el foco puede salir del drawer.
Controlado
Pasa open y onOpenChange para abrirlo desde cualquier lugar, sin un trigger.
Triggers desacoplados
Comparte un drawer entre varios triggers con createDrawerHandle. Cada trigger pasa un payload que el drawer renderiza mediante un hijo de tipo función.
De derecha a izquierda
Pasa dir="rtl" a <DrawerContent /> para reflejar su contenido. swipeDirection nombra un borde físico, así que "left" sigue a la izquierda y el tirador permanece en el borde interior.
| Key | Acción |
|---|---|
| EnterSpace | En el trigger, abre el drawer y mueve el foco dentro de él. |
| TabShift + Tab | Se mueve entre elementos enfocables. El foco permanece dentro de un drawer modal. |
| Esc | Cierra el drawer superior y devuelve el foco a su trigger. |
- El drawer es un diálogo.
<DrawerTitle />lo etiqueta y<DrawerDescription />lo describe, así que incluye siempre un título. - Deslizar nunca es la única salida: Escape, el fondo y un botón
<DrawerClose />también lo cierran. - El tirador es decorativo y está oculto para las tecnologías de asistencia. Con un ratón, el texto dentro del drawer se puede seleccionar sin arrastrarlo.
- Con movimiento reducido activado, el drawer aparece y desaparece con un fundido en lugar de deslizarse. El arrastre sigue al puntero.
Construido sobre el drawer de Base UI. Cada parte acepta las props de la primitiva que envuelve.
| Prop | Tipo | Predeterminado |
|---|---|---|
swipeDirectionEl borde desde el que se abre y la dirección que lo descarta. | "up" | "down" | "left" | "right" | "down" |
showSwipeHandleMuestra el tirador. Por defecto es true para up y down, y false para left y right. | boolean | – |
snapPointsAlturas en las que puede reposar un drawer vertical. 0–1 es una fracción del viewport, >1 son píxeles, las cadenas aceptan px o rem. | (number | string)[] | – |
snapPoint | number | string | null | – |
defaultSnapPoint | number | string | null | – |
onSnapPointChange | (snapPoint, details) => void | – |
defaultOpen | boolean | false |
open | boolean | – |
onOpenChange | (open: boolean, details) => void | – |
onOpenChangeCompleteSe llama cuando termina la animación de apertura o cierre. | (open: boolean) => void | – |
modalEl fondo solo se renderiza cuando es true. | boolean | "trap-focus" | true |
disablePointerDismissalLo mantiene abierto al hacer clic en el fondo. | boolean | false |
handle | DrawerHandle<Payload> | – |
children | ReactNode | ({ payload }) => ReactNode | – |
| Prop | Tipo | Predeterminado |
|---|---|---|
handle | DrawerHandle<Payload> | – |
payload | Payload | – |
render | ReactElement | (props, state) => ReactElement | <button> |
| Atributo | Descripción |
|---|---|
data-slot="drawer-trigger" | Apunta al trigger en CSS. |
data-popup-open | Presente mientras su drawer está abierto. |
Renderiza el portal, el fondo, el viewport y el popup, además del tirador. Los drawers verticales se ajustan a su contenido hasta la altura del viewport menos 4rem. Los drawers laterales ocupan el 75% del ancho, hasta 24rem desde el breakpoint sm. Reemplázalo con h-* o w-*, o limítalo a un eje con data-[swipe-axis=y]:.
| Prop | Tipo | Predeterminado |
|---|---|---|
initialFocus | boolean | RefObject | (type) => HTMLElement | boolean | – |
finalFocus | boolean | RefObject | (type) => HTMLElement | boolean | – |
className | string | (state) => string | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Atributo | Descripción |
|---|---|
data-slot="drawer-popup" | El panel del drawer. |
data-slot="drawer-content" | El contenedor interior alrededor de tus hijos. Se desplaza cuando nada más lo hace. |
data-swipe-direction | up, right, down o left. |
data-swipe-axis | x o y. |
data-open | Presente mientras el drawer está abierto. |
data-starting-style | Presente mientras se anima la entrada. |
data-ending-style | Presente mientras se anima la salida. |
data-swiping | Presente mientras se arrastra. |
data-snap-points | Presente cuando el drawer tiene puntos de ajuste. |
data-expanded | Presente en el punto de ajuste de altura completa. |
data-nested-drawer-open | Presente mientras otro drawer está abierto encima. |
data-stack | Presente mientras un drawer del mismo borde está apilado encima. |
--drawer-inset | Separa el drawer flotante de los bordes del viewport. Por defecto 0px. |
--drawer-bleed-background | Rellena el área que se revela al arrastrar más allá de su borde. Por defecto es el color del popover. |
--drawer-swipe-movement-x | Distancia de arrastre horizontal. También existe una variable -y. |
--drawer-snap-point-offset | A qué distancia bajo la parte superior está el punto de ajuste actual. |
--nested-drawers | Cuántos drawers están abiertos encima. |
Lo renderiza <DrawerContent /> cuando modal es true. Se desvanece al deslizar y permanece al menos medio visible cuando hay puntos de ajuste. Un drawer superpuesto a un sheet o a un drawer de otro borde recibe un fondo más claro.
| Atributo | Descripción |
|---|---|
data-slot="drawer-overlay" | El fondo. |
data-nested | Presente en los fondos más claros de drawers superpuestos. |
--drawer-overlay-min-opacity | La opacidad mínima a la que se desvanece al deslizar. 0, o 0.5 con puntos de ajuste. |
Lo renderiza <DrawerContent /> en el borde interior cuando showSwipeHandle está activado. Se puede arrastrar todo el drawer, así que el tirador es una pista visual.
| Atributo | Descripción |
|---|---|
data-slot="drawer-swipe-handle" | El tirador. |
Elementos <div> simples que organizan el drawer. El encabezado centra su texto en drawers verticales en pantallas pequeñas, el cuerpo se desplaza y ocupa el espacio restante, y el pie apila sus acciones.
| Atributo | Descripción |
|---|---|
data-slot="drawer-header" | Título y descripción. |
data-slot="drawer-body" | Contenido desplazable. |
data-slot="drawer-footer" | Acciones. |
| Prop | Tipo | Predeterminado |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <h2> |
| Atributo | Descripción |
|---|---|
data-slot="drawer-title" | Etiqueta el drawer. |
| Prop | Tipo | Predeterminado |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <p> |
| Atributo | Descripción |
|---|---|
data-slot="drawer-description" | Describe el drawer. |
No renderiza ningún elemento. Colócalo dentro de <Drawer />, alrededor de <DrawerContent />. Mientras el teclado de software está abierto, añade espacio bajo el contenedor de desplazamiento del drawer, desplaza el campo con foco hasta hacerlo visible y hace que tocar los campos abra el teclado en iOS. Los drawers sin él no se ven afectados.
| Prop | Tipo | Predeterminado |
|---|---|---|
children | ReactNode | – |
| Atributo | Descripción |
|---|---|
--drawer-keyboard-inset | Se define en el viewport mientras el teclado está abierto: cuánto de él se superpone a la página. Úsalo con un valor de respaldo de 0px. |
| Prop | Tipo | Predeterminado |
|---|---|---|
render | ReactElement | (props, state) => ReactElement | <button> |
| Atributo | Descripción |
|---|---|
data-slot="drawer-close" | Cierra el drawer al pulsarlo. |
createDrawerHandle<Payload>() devuelve un handle que conecta un <Drawer /> con triggers renderizados en otro lugar. Créalo una sola vez, fuera de tu componente.
- SheetUn panel que se desliza desde cualquier borde, con deslizamiento para descartar, bloqueo de scroll y anidamiento apilado.
- 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.
- Dropdown menuUn menú de acciones y opciones tras un botón, con grupos, submenús, elementos de casilla y de radio, y atajos.
Usado en bloques
Bloques que se construyen sobre Drawer.