GrTabPanels
Renders tab panels linked to `GrTabs` by ARIA for accessible tabs.
Machine-translated from the Russian original, not yet reviewed. Read the original
When to take it
- the tabs need panels — the component links them to
GrTabsby ARIA, with no manualids; - a panel is heavy — lazy mounting does not build the content until the first showing;
- the state of a panel has to be kept — a hidden panel stays mounted, and what was typed into it is not lost;
- the layout of the tabs is your own — the panels stand separately from the list of tabs rather than under it.
When to take something else
| Need | Take |
|---|---|
| The list of tabs itself is needed | GrTabs |
| The sections expand rather than switch | GrCollapse |
| The view of one piece of content is switched | GrSegmented |
`keepAlive` and `lazy`
By default an inactive panel is not in the DOM. keepAlive leaves it hidden (hidden) — the state
of the forms is not lost. lazy adds “do not mount until it has been shown for the first time” to
that: together they give “mount once on demand and never destroy again”.
keepAlive | lazy | The behaviour |
|---|---|---|
| — | — | the panel is mounted when shown and unmounted when left |
| ✓ | — | all of the panels are in the DOM at once, the inactive ones hidden |
| ✓ | ✓ | the panel appears in the DOM on the first showing and stays |
Playground 2
Loading…
<GrTabPanels />Install
npm i @feugene/granularityImport
import { GrTabPanels } from '@feugene/granularity/components/GrTabPanels'API
Props
| Prop | Type | default | Description |
|---|---|---|---|
idBase | string | undefined | undefined | — |
modelValuerequired | string | — | — |
Slots
| Slot | Type | Description |
|---|---|---|
default | any | The panels (`GrTabPanel`). |
Examples 2
Keep Alive
draft — состояние поля не теряется
Смонтированы: draft. Панель появляется в DOM при первом показе и дальше не разрушается.
<script setup lang="ts">
import { ref } from 'vue'
import { GrInput, GrTabPanel, GrTabPanels, GrTabs } from '@feugene/granularity'
const tab = ref('draft')
const draft = ref('Черновик переживает переключение вкладок')
const mounted = ref<string[]>([])
const tabs = [
{ value: 'draft', label: 'Черновик' },
{ value: 'preview', label: 'Предпросмотр' },
{ value: 'history', label: 'История' },
]
function markMounted(value: string): string {
if (!mounted.value.includes(value))
mounted.value = [...mounted.value, value]
return value
}
</script>
<template>
<div class="grid gap-4">
<GrTabs v-model="tab" :tabs="tabs" id-base="keep-alive-demo" />
<!-- `keepAlive` + `lazy`: панель монтируется при первом показе и дальше живёт. -->
<GrTabPanels v-model="tab" id-base="keep-alive-demo">
<GrTabPanel value="draft" keep-alive lazy>
<div class="grid gap-2 p-3">
<span class="text-sm text-[var(--gr-muted-fg)]">{{ markMounted('draft') }} — состояние поля не теряется</span>
<GrInput v-model="draft" size="sm" aria-label="Черновик" />
</div>
</GrTabPanel>
<GrTabPanel value="preview" keep-alive lazy>
<div class="p-3 text-sm">
{{ markMounted('preview') }}: {{ draft || '—' }}
</div>
</GrTabPanel>
<GrTabPanel value="history" keep-alive lazy>
<div class="p-3 text-sm text-[var(--gr-muted-fg)]">
{{ markMounted('history') }} — панель смонтировалась только сейчас
</div>
</GrTabPanel>
</GrTabPanels>
<div class="rounded-2xl border border-dashed border-[var(--gr-brd)] p-3 text-sm text-[var(--gr-muted-fg)]">
Смонтированы: <span class="font-semibold text-[var(--gr-fg)]">{{ mounted.join(', ') || '—' }}</span>.
Панель появляется в DOM при первом показе и дальше не разрушается.
</div>
</div>
</template>Accessible tabs with linked panels
Overview: a summary of the workspace.
<script setup lang="ts">
import { ref } from 'vue'
import { GrTabPanel, GrTabPanels, GrTabs, type GrTab } from '@feugene/granularity'
const active = ref('overview')
const tabs: GrTab[] = [
{ value: 'overview', label: 'Overview' },
{ value: 'activity', label: 'Activity', badge: '3' },
{ value: 'settings', label: 'Settings' },
]
</script>
<template>
<!-- Одинаковый `id-base` связывает вкладки и панели по ARIA (aria-controls ↔ aria-labelledby). -->
<div class="grid max-w-lg gap-3">
<GrTabs v-model="active" :tabs="tabs" id-base="demo-tabs" />
<GrTabPanels
v-model="active"
id-base="demo-tabs"
class="rounded-xl border border-[var(--gr-brd)] bg-[var(--gr-card)] p-4 text-sm text-[var(--gr-fg)]"
>
<GrTabPanel value="overview">Overview: a summary of the workspace.</GrTabPanel>
<GrTabPanel value="activity">Activity: 3 new items since your last visit.</GrTabPanel>
<GrTabPanel value="settings">Settings: manage members and preferences.</GrTabPanel>
</GrTabPanels>
</div>
</template>