GrTabPanels
Берут, когда к вкладкам нужны панели.
Когда брать
- к вкладкам нужны панели — компонент связывает их с
GrTabsпо ARIA, без ручныхid; - панель тяжёлая — ленивое монтирование не строит содержимое до первого показа;
- состояние панели надо сохранить — скрытая панель остаётся смонтированной, и введённое в ней не пропадает;
- раскладка вкладок своя — панели стоят отдельно от списка вкладок, а не под ним.
Когда взять другое
| Нужно | Берите |
|---|---|
| Нужен сам список вкладок | GrTabs |
| Разделы раскрываются, а не переключаются | GrCollapse |
| Переключается вид одного содержимого | GrSegmented |
Связка держится на общем `idBase`
<GrTabs v-model="tab" :tabs="tabs" id-base="settings" />
<GrTabPanels v-model="tab" id-base="settings">
<GrTabPanel value="profile">…</GrTabPanel>
<GrTabPanel value="billing">…</GrTabPanel>
</GrTabPanels>
idBase реактивен: его изменение доезжает до панелей. Раньше он вычислялся
один раз при setup — панели оставались со старыми id, GrTabs уезжал на новые,
и aria-controls ↔ aria-labelledby разъезжались молча.
Без idBase он генерируется сам, но тогда его не увидит GrTabs: панель
сошлётся на несуществующую вкладку. В dev-сборке это выводится
предупреждением — тем же приёмом, каким GrFormField ловит забытый контрол.
`keepAlive` и `lazy`
По умолчанию неактивная панель не в DOM. keepAlive оставляет её скрытой
(hidden) — состояние форм не теряется. lazy добавляет к этому «не
монтировать, пока не показали впервые»: вместе они дают «смонтировать один раз
по требованию и больше не разрушать».
keepAlive | lazy | Поведение |
|---|---|---|
| — | — | панель монтируется при показе, размонтируется при уходе |
| ✓ | — | все панели в DOM сразу, неактивные скрыты |
| ✓ | ✓ | панель появляется в DOM при первом показе и остаётся |
Playground 2
Загружается…
<GrTabPanels />Установка
npm i @feugene/granularityИмпорт
import { GrTabPanels } from '@feugene/granularity/components/GrTabPanels'API
Props
| Prop | Type | по умолчанию | Описание |
|---|---|---|---|
idBase | string | undefined | undefined | — |
modelValueобязательный | string | — | — |
Slots
| Slot | Type | Описание |
|---|---|---|
default | any | Панели (`GrTabPanel`). |
Примеры 2
keepAlive и ленивое монтирование
Панель монтируется при первом показе (lazy) и дальше не разрушается (keepAlive) — состояние формы переживает переключение.
<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>Доступные вкладки со связанными панелями
Companion к GrTabs: одинаковый id-base связывает вкладки и панели по ARIA (aria-controls ↔ aria-labelledby). Показывается панель активной вкладки; keep-alive оставляет неактивные в DOM.
<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>