Cajón
Panel lateral que se desliza desde el borde de la pantalla; resulta adecuado para operaciones temporales más pegadas a los bordes que un Dialog (detalles, filtrado, pasos de un asistente). Al igual que Dialog, emplea role="dialog" + aria-modal="true", el foco queda encerrado en el panel y tanto Esc como el clic en la máscara pueden cerrarlo.
Uso básico
<template>
<LhButton @click="basic = true">Abrir cajón</LhButton>
<LhDrawer v-model="basic" title="Detalles del pedido">
<p>Aquí se coloca el contenido principal del cajón.</p>
</LhDrawer>
</template>
<script setup lang="ts">
import { ref } from 'vue'
const basic = ref(false)
</script><script>
export default {
data() {
return { basic: false }
},
}
</script>
<template>
<LhButton @click="basic = true">Abrir cajón</LhButton>
<LhDrawer v-model="basic" title="Detalles del pedido">
<p>Aquí se coloca el contenido principal del cajón.</p>
</LhDrawer>
</template>Cuatro direcciones
<script setup lang="ts">
import { ref } from 'vue'
const dirVisible = ref(false)
const direction = ref<'right' | 'left' | 'top' | 'bottom'>('right')
const size = ref('40%')
function openDir(d: 'right' | 'left' | 'top' | 'bottom') {
direction.value = d
dirVisible.value = true
}
</script>
<template>
<!-- Abrir el cajón derecho -->
<LhButton @click="openDir('right')">right</LhButton>
<!-- Abrir el cajón izquierdo -->
<LhButton @click="openDir('left')">left</LhButton>
<!-- Abrir el cajón superior -->
<LhButton @click="openDir('top')">top</LhButton>
<!-- Abrir el cajón inferior -->
<LhButton @click="openDir('bottom')">bottom</LhButton>
<!-- Se desliza en la dirección indicada -->
<LhDrawer v-model="dirVisible" :title="`Cajón ${direction}`" :direction="direction" :size="size">
<p>Dirección actual: {{ direction }}</p>
</LhDrawer>
</template><script>
export default {
data() {
return { dirVisible: false, direction: 'right', size: '40%' }
},
methods: {
openDir(d) {
this.direction = d
this.dirVisible = true
},
},
}
</script>
<template>
<!-- Abrir el cajón derecho -->
<LhButton @click="openDir('right')">right</LhButton>
<!-- Abrir el cajón izquierdo -->
<LhButton @click="openDir('left')">left</LhButton>
<!-- Abrir el cajón superior -->
<LhButton @click="openDir('top')">top</LhButton>
<!-- Abrir el cajón inferior -->
<LhButton @click="openDir('bottom')">bottom</LhButton>
<!-- Se desliza en la dirección indicada -->
<LhDrawer v-model="dirVisible" :title="`Cajón ${direction}`" :direction="direction" :size="size">
<p>Dirección actual: {{ direction }}</p>
</LhDrawer>
</template>Tamaño personalizado y zona inferior
<script setup lang="ts">
import { ref } from 'vue'
const sized = ref(false)
</script>
<template>
<!-- Abrir un cajón de 480 px de ancho -->
<LhButton @click="sized = true">Cajón de 480 px de ancho</LhButton>
<!-- Cajón de tamaño fijo; la zona inferior es el área de acciones -->
<LhDrawer v-model="sized" title="Condiciones del filtro" :size="480">
<LhInput placeholder="Filtrar por nombre" />
<LhInput placeholder="Filtrar por etiqueta" />
<template #footer>
<LhButton @click="sized = false">Cancelar</LhButton>
<LhButton type="primary" @click="sized = false">Aplicar filtro</LhButton>
</template>
</LhDrawer>
</template><script>
export default {
data() {
return { sized: false }
},
}
</script>
<template>
<!-- Abrir un cajón de 480 px de ancho -->
<LhButton @click="sized = true">Cajón de 480 px de ancho</LhButton>
<!-- Cajón de tamaño fijo; la zona inferior es el área de acciones -->
<LhDrawer v-model="sized" title="Condiciones del filtro" :size="480">
<LhInput placeholder="Filtrar por nombre" />
<LhInput placeholder="Filtrar por etiqueta" />
<template #footer>
<LhButton @click="sized = false">Cancelar</LhButton>
<LhButton type="primary" @click="sized = false">Aplicar filtro</LhButton>
</template>
</LhDrawer>
</template>Si
sizerecibe un número, se interpreta como px; si recibe una cadena, admite porcentajes (p. ej.,'40%'). En las direcciones izquierda/derecha actúa sobre la anchura, y en las direcciones superior/inferior, sobre la altura.
Interruptores de comportamiento
mask-closable impide el cierre al hacer clic en la máscara; show-close oculta el botón de cierre de la esquina superior derecha; close-on-esc desactiva el cierre con Esc; lock-scroll evita que se bloquee el desplazamiento de la página al abrir; teleport-target especifica el contenedor de montaje.
<script setup lang="ts">
import { ref } from 'vue'
const adv1 = ref(false)
const adv2 = ref(false)
const adv3 = ref(false)
</script>
<template>
<!-- Abrir el cajón «Cerrar solo con el botón» -->
<LhButton @click="adv1 = true">Cerrar solo con el botón</LhButton>
<!-- Abrir el cajón «Sin bloqueo del desplazamiento» -->
<LhButton @click="adv2 = true">Sin bloqueo del desplazamiento</LhButton>
<!-- Ni el clic en la máscara ni Esc cierran el panel -->
<LhDrawer
v-model="adv1"
title="Cerrar solo con el botón"
:mask-closable="false"
:show-close="false"
:close-on-esc="false"
>
<p>Ni el clic en la máscara ni Esc cierran el panel: solo puede cerrarse con el botón.</p>
<template #footer>
<LhButton type="primary" @click="adv1 = false">Cerrar</LhButton>
</template>
</LhDrawer>
<!-- Al abrir, la página sigue pudiéndose desplazar -->
<LhDrawer v-model="adv2" title="Sin bloqueo del desplazamiento" :lock-scroll="false">
<p>Con el cajón abierto, la página sigue pudiéndose desplazar.</p>
</LhDrawer>
<!-- Montar en el contenedor especificado -->
<LhDrawer v-model="adv3" title="Contenedor de montaje especificado" teleport-target="#drawer-host">
<p>El panel se transmite al contenedor cuyo id es drawer-host.</p>
</LhDrawer>
</template><script>
export default {
data() {
return { adv1: false, adv2: false, adv3: false }
},
}
</script>
<template>
<!-- Abrir el cajón «Cerrar solo con el botón» -->
<LhButton @click="adv1 = true">Cerrar solo con el botón</LhButton>
<!-- Abrir el cajón «Sin bloqueo del desplazamiento» -->
<LhButton @click="adv2 = true">Sin bloqueo del desplazamiento</LhButton>
<!-- Ni el clic en la máscara ni Esc cierran el panel -->
<LhDrawer
v-model="adv1"
title="Cerrar solo con el botón"
:mask-closable="false"
:show-close="false"
:close-on-esc="false"
>
<p>Ni el clic en la máscara ni Esc cierran el panel: solo puede cerrarse con el botón.</p>
<template #footer>
<LhButton type="primary" @click="adv1 = false">Cerrar</LhButton>
</template>
</LhDrawer>
<!-- Al abrir, la página sigue pudiéndose desplazar -->
<LhDrawer v-model="adv2" title="Sin bloqueo del desplazamiento" :lock-scroll="false">
<p>Con el cajón abierto, la página sigue pudiéndose desplazar.</p>
</LhDrawer>
<!-- Montar en el contenedor especificado -->
<LhDrawer v-model="adv3" title="Contenedor de montaje especificado" teleport-target="#drawer-host">
<p>El panel se transmite al contenedor cuyo id es drawer-host.</p>
</LhDrawer>
</template>Drawer API
Props
| Prop | Descripción | Tipo | Predeterminado |
|---|---|---|---|
| modelValue | Si se muestra (v-model) | boolean | — |
| title | Título (también puede usar el slot header) | string | — |
| direction | Dirección | "right" | "left" | "top" | "bottom" | 'right' |
| size | Tamaño: un número son px; una cadena admite porcentajes | string | number | '30%' |
| maskClosable | Si se cierra al hacer clic en la máscara | boolean | true |
| showClose | Si se muestra el botón de cierre | boolean | true |
| teleportTarget | Objetivo del Teleport (selector o elemento; por defecto, body) | string | HTMLElement | 'body' |
| lockScroll | Si se bloquea el desplazamiento de la página | boolean | true |
| closeOnEsc | Si responde al cierre con Esc | boolean | true |
| themeVars | Variables de tema a nivel de componente; sobrescribe la configuración del ConfigProvider | { [x: string]: string; } | — |
| bgPattern | Patrón de fondo a nivel de componente; sobrescribe la configuración del ConfigProvider | string | — |
| sx | Props de disposición rápida (aplicadas al panel) | LhSxProps | — |
Events
| Evento | Descripción | Parámetros |
|---|---|---|
| update:model-value | Cambio de visibilidad | (value: boolean) |
| open | Se dispara tras abrir | — |
| close | Se dispara tras cerrar | — |
Slots
| Slot | Descripción |
|---|---|
| default | Contenido principal |
| header | Cabecera personalizada (incluye la zona del título) |
| footer | Zona inferior de acciones personalizada |
Methods
| Método | Descripción |
|---|---|
| open | Apertura programática |
| close | Cierre programático |
Accesibilidad
role="dialog"+aria-modal="true"; cuando hay título se asocia mediantearia-labelledby, y cuando no lo hay se usadrawer.titledel paquete de idioma como valor de respaldo de aria-label- Al abrirse, el foco pasa al primer elemento enfocable del panel; Tab queda encerrado en el panel y, al cerrar, el foco regresa al elemento que lo abrió
- Cierre con Esc (puede desactivarse con
close-on-esc); la máscara es decorativa (aria-hidden) - El botón de cierre es un
<button>real; su aria-label procede dedrawer.closedel paquete de idioma - La animación de deslizamiento al entrar y salir se degrada a un simple fundido cuando está activo
prefers-reduced-motion
Definiciones de tipos
Las estructuras de tipos TypeScript exportadas por este componente (extraídas automáticamente de packages/components/drawer/src/types.ts y de las fuentes @lh-ui/share/core/*; abre cada entrada para ver la definición completa; la descripción de los atributos está en la tabla de Props de arriba):
LhDrawerProps
export interface LhDrawerProps {
/** Si se muestra (v-model) */
modelValue?: boolean
/** Título */
title?: string
/** Dirección */
direction?: LhDrawerDirection
/** Tamaño: un número son px; una cadena admite porcentajes */
size?: string | number
/** Si se cierra al hacer clic en la máscara */
maskClosable?: boolean
/** Si se muestra el botón de cierre */
showClose?: boolean
/** Objetivo del Teleport (selector o elemento; por defecto, body) */
teleportTarget?: string | HTMLElement
/** Si se bloquea el desplazamiento de la página */
lockScroll?: boolean
/** Si responde al cierre con Esc */
closeOnEsc?: boolean
/** Variables de tema a nivel de componente; sobrescribe la configuración del ConfigProvider */
themeVars?: Record<string, string>
/** Patrón de fondo a nivel de componente; sobrescribe la configuración del ConfigProvider */
bgPattern?: string
/** Props de disposición rápida (aplicadas al panel) */
sx?: LhSxProps
}LhDrawerDirection (de @lh-ui/share/core/drawer (logic.ts))
/**
* Lógica de funciones puras de Drawer (sin dependencias de framework)
*/
/** Dirección del cajón */
export type LhDrawerDirection = 'right' | 'left' | 'top' | 'bottom'