Pestañas
Cambio de contenido del mismo nivel. Sigue de forma estricta el patrón de pestañas de WAI-ARIA APG: tres roles vinculados tablist/tab/tabpanel + roving tabindex + navegación con las teclas de dirección.
Uso básico
<script setup lang="ts">
</script>
<template>
<LhTabs>
<LhTabPane name="prose" label="Prosa">Contenido de prosa a tinta.</LhTabPane>
<LhTabPane name="poem" label="Poesía">Contenido de métrica poética.</LhTabPane>
<LhTabPane name="calligraphy" label="Caligrafía">Contenido de caligrafía y lápidas.</LhTabPane>
</LhTabs>
</template><script>
export default {}
</script>
<template>
<LhTabs>
<LhTabPane name="prose" label="Prosa">Contenido de prosa a tinta.</LhTabPane>
<LhTabPane name="poem" label="Poesía">Contenido de métrica poética.</LhTabPane>
<LhTabPane name="calligraphy" label="Caligrafía">Contenido de caligrafía y lápidas.</LhTabPane>
</LhTabs>
</template>Aspecto de tarjeta y deshabilitado
<script setup lang="ts">
</script>
<template>
<LhTabs type="card">
<LhTabPane name="ink" label="Tinta">La tinta tiene cinco tonos.</LhTabPane>
<LhTabPane name="cinnabar" label="Bermellón" disabled>El cinabrio no se puede usar.</LhTabPane>
<LhTabPane name="gold" label="Oro">Toques de amarillo reseda.</LhTabPane>
</LhTabs>
</template><script>
export default {}
</script>
<template>
<LhTabs type="card">
<LhTabPane name="ink" label="Tinta">La tinta tiene cinco tonos.</LhTabPane>
<LhTabPane name="cinnabar" label="Bermellón" disabled>El cinabrio no se puede usar.</LhTabPane>
<LhTabPane name="gold" label="Oro">Toques de amarillo reseda.</LhTabPane>
</LhTabs>
</template>Posición inferior
<script setup lang="ts">
</script>
<template>
<LhTabs tab-position="bottom">
<LhTabPane name="mountain" label="Montaña">La montaña tiene una robusta presencia.</LhTabPane>
<LhTabPane name="water" label="Agua">El agua transmite un sentido de vacío y ligereza.</LhTabPane>
</LhTabs>
</template><script>
export default {}
</script>
<template>
<LhTabs tab-position="bottom">
<LhTabPane name="mountain" label="Montaña">La montaña tiene una robusta presencia.</LhTabPane>
<LhTabPane name="water" label="Agua">El agua transmite un sentido de vacío y ligereza.</LhTabPane>
</LhTabs>
</template>Cerrable y añadir
<script setup lang="ts">
import { ref } from 'vue'
const panes = ref([
{ name: 's1', label: 'Rollo de pintura 1', content: 'Contenido del primer rollo.', disabled: false },
{ name: 's2', label: 'Rollo de pintura 2', content: 'Contenido del segundo rollo.', disabled: false },
])
let index = 2
const removePane = (name) => {
const target = panes.value.find((pane) => pane.name === name)
if (target) panes.value.splice(panes.value.indexOf(target), 1)
}
const addPane = () => {
index += 1
panes.value.push({ name: `s${index}`, label: `Rollo de pintura ${index}`, content: 'Contenido del rollo nuevo.', disabled: false })
}
</script>
<template>
<!-- Cerrable y añadir -->
<LhTabs closable addable tab-position="bottom" @tab-remove="removePane" @tab-add="addPane">
<LhTabPane
v-for="pane in panes"
:key="pane.name"
:name="pane.name"
:label="pane.label"
:disabled="pane.disabled"
>{{ pane.content }}</LhTabPane>
</LhTabs>
</template><script>
export default {
data() {
return {
panes: [
{ name: 's1', label: 'Rollo de pintura 1', content: 'Contenido del primer rollo.', disabled: false },
{ name: 's2', label: 'Rollo de pintura 2', content: 'Contenido del segundo rollo.', disabled: false },
],
index: 2,
}
},
methods: {
removePane(name) {
const target = this.panes.find((pane) => pane.name === name)
if (target) this.panes.splice(this.panes.indexOf(target), 1)
},
addPane() {
this.index += 1
this.panes.push({ name: `s${this.index}`, label: `Rollo de pintura ${this.index}`, content: 'Contenido del rollo nuevo.', disabled: false })
},
},
}
</script>
<template>
<!-- Cerrable y añadir -->
<LhTabs closable addable tab-position="bottom" @tab-remove="removePane" @tab-add="addPane">
<LhTabPane
v-for="pane in panes"
:key="pane.name"
:name="pane.name"
:label="pane.label"
:disabled="pane.disabled"
>{{ pane.content }}</LhTabPane>
</LhTabs>
</template>Al cerrar la pestaña activa, el componente conmuta de forma coordinada a la pestaña disponible adyacente y emite
tab-remove; es responsabilidad de quien lo usa eliminar el pane correspondiente del origen de datos.
Uso controlado
Pestaña actual: mo
<script setup lang="ts">
import { ref } from 'vue'
const active = ref('mo')
</script>
<template>
<LhTabs v-model="active" type="card">
<LhTabPane name="zh" label="Estilo nacional">Contenido de estilo nacional.</LhTabPane>
<LhTabPane name="mo" label="Tinta">Contenido de tinta.</LhTabPane>
</LhTabs>
</template><script>
export default {
data() {
return { active: 'mo' }
},
}
</script>
<template>
<LhTabs v-model="active" type="card">
<LhTabPane name="zh" label="Estilo nacional">Contenido de estilo nacional.</LhTabPane>
<LhTabPane name="mo" label="Tinta">Contenido de tinta.</LhTabPane>
</LhTabs>
</template>Tabs API
LhTabs Props
| Prop | Descripción | Tipo | Predeterminado |
|---|---|---|---|
| modelValue | name de la pestaña activada actualmente (v-model) | string | — |
| type | Aspecto | "line" | "card" | 'line' |
| closable | Si las pestañas se pueden cerrar | boolean | false |
| addable | Si se muestra el botón de añadir | boolean | false |
| tabPosition | Posición de las pestañas | "top" | "bottom" | 'top' |
| sx | Props de maquetación rápida sx | LhSxProps | — |
LhTabs Events
| Evento | Descripción | Parámetro |
|---|---|---|
| update:modelValue | Cambio de la pestaña activada (v-model) | (name: string) |
| tab-change | Cambio de la pestaña activada | (name: string) |
| tab-remove | Cierre de una pestaña | (name: string) |
| tab-add | Pulsación del botón de añadir | — |
LhTabPane Props
| Prop | Descripción | Tipo | Predeterminado |
|---|---|---|---|
| name | Identificador único de la pestaña (clave estable; no se recomienda modificarlo de forma dinámica) | string | — |
| label | Título de la pestaña | string | '' |
| disabled | Si se deshabilita | boolean | false |
Slots
| Slot | Descripción | Componente afín |
|---|---|---|
| default | Paneles de pestaña (lista de LhTabPane) | LhTabs |
| default | Contenido del panel | LhTabPane |
Accesibilidad
Sigue de forma estricta el patrón de pestañas de WAI-ARIA APG:
- La cabecera de las pestañas es
role="tablist", cada pestaña esrole="tab"(aria-selected+aria-controls) y el panel esrole="tabpanel"(aria-labelledby+tabindex="0") - Roving tabindex: solo la pestaña activada puede recibir el foco con Tab; las demás tienen
tabindex="-1" - Las teclas de dirección se mueven entre las pestañas disponibles y las activan automáticamente (saltándose las deshabilitadas); Home/End salta al principio y al final
- Con
closable, la tecla Delete cierra la pestaña actual; el icono de cierre es decorativo (aria-hidden) y el teclado usa Delete, para evitar anidar un botón dentro de otro - Las pestañas deshabilitadas no se pueden enfocar ni activar; acciones como
tab-removeno tienen efecto sobre los elementos deshabilitados
Definiciones de tipos
Las estructuras de tipos TypeScript que exporta este componente son las siguientes (extraídas automáticamente de packages/components/tabs/src/types.ts y del código fuente de @lh-ui/share/core/*; despliega cada entrada para ver la definición completa; la descripción de los atributos está en la tabla de Props de arriba):
LhTabsProps
export interface LhTabsProps {
/** name de la pestaña activada actualmente (v-model) */
modelValue?: string
/** Aspecto */
type?: LhTabsType
/** Si las pestañas se pueden cerrar */
closable?: boolean
/** Si se muestra el botón de añadir */
addable?: boolean
/** Posición de las pestañas */
tabPosition?: LhTabsPosition
/** Props de maquetación rápida sx */
sx?: LhSxProps
}LhTabPaneProps
export interface LhTabPaneProps {
/** Identificador único de la pestaña (clave estable; no se recomienda modificarlo de forma dinámica) */
name: string
/** Título de la pestaña */
label?: string
/** Si se deshabilita */
disabled?: boolean
}LhTabsType (de @lh-ui/share/core/tabs)
/**
* Aspecto de las pestañas
*/
export type LhTabsType = 'line' | 'card'LhTabsPosition (de @lh-ui/share/core/tabs)
/**
* Posición de las pestañas
*/
export type LhTabsPosition = 'top' | 'bottom'