GrTabPanels

Пакет: @feugene/granularityядроГруппа: Навигация

Берут, когда к вкладкам нужны панели.

Когда брать

  • к вкладкам нужны панели — компонент связывает их с 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-controlsaria-labelledby разъезжались молча.

Без idBase он генерируется сам, но тогда его не увидит GrTabs: панель сошлётся на несуществующую вкладку. В dev-сборке это выводится предупреждением — тем же приёмом, каким GrFormField ловит забытый контрол.

`keepAlive` и `lazy`

По умолчанию неактивная панель не в DOM. keepAlive оставляет её скрытой (hidden) — состояние форм не теряется. lazy добавляет к этому «не монтировать, пока не показали впервые»: вместе они дают «смонтировать один раз по требованию и больше не разрушать».

keepAlivelazyПоведение
панель монтируется при показе, размонтируется при уходе
все панели в DOM сразу, неактивные скрыты
панель появляется в DOM при первом показе и остаётся

Playground 2

Загружается…

Код
<GrTabPanels />

Установка

npm i @feugene/granularity

Импорт

import { GrTabPanels } from '@feugene/granularity/components/GrTabPanels'

API

Props

PropTypeпо умолчаниюОписание
idBasestring | undefinedundefined
modelValueобязательныйstring

Slots

SlotTypeОписание
defaultanyПанели (`GrTabPanel`).

Примеры 2

keepAlive и ленивое монтирование

Панель монтируется при первом показе (lazy) и дальше не разрушается (keepAlive) — состояние формы переживает переключение.

draft — состояние поля не теряется
Смонтированы: draft. Панель появляется в DOM при первом показе и дальше не разрушается.

Keep Alive
<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-controlsaria-labelledby). Показывается панель активной вкладки; keep-alive оставляет неактивные в DOM.

Overview: a summary of the workspace.

Basic
<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>

Документация компонентаВсе компоненты