PXD

Tabs

Display tab content.

Tabs are driven by the options prop; the tab bar and every panel are rendered by PTabs itself, so the markup also exists in server-rendered HTML.

This is overview tab content.
<script setup lang="ts">
import { ref } from 'vue'

const value = ref('overview')

const options = [
  { label: 'Overview', value: 'overview' },
  { label: 'Account', value: 'account' },
  { disabled: true, label: 'Settings', value: 'settings' },
]
</script>

<template>
  <PTabs v-model="value" :options="options">
    <template #item="{ option }">
      This is {{ option.value }} tab content.
    </template>
  </PTabs>
</template>

Label slot

Use the label slot when a trigger needs more than plain text. It receives the same { option, active } scope as the item slot.

inbox content
<script setup lang="ts">
import { ref } from 'vue'

const value = ref('inbox')

const options = [
  { label: 'Inbox', value: 'inbox' },
  { label: 'Archive', value: 'archive' },
]
</script>

<template>
  <PTabs v-model="value" :options="options">
    <template #label="{ option }">
      <PBadge>{{ option.label }}</PBadge>
    </template>

    <template #item="{ option }">
      {{ option.value }} content
    </template>
  </PTabs>
</template>

Secondary

This is overview tab content.
<script setup lang="ts">
import { ref } from 'vue'

const value = ref('overview')

const options = [
  { label: 'Overview', value: 'overview' },
  { label: 'Account', value: 'account' },
  { disabled: true, label: 'Settings', value: 'settings' },
]
</script>

<template>
  <PTabs v-model="value" variant="secondary" :options="options">
    <template #item="{ option }">
      This is {{ option.value }} tab content.
    </template>
  </PTabs>
</template>

Segmented

This is overview tab content.
<script setup lang="ts">
import { ref } from 'vue'

const value = ref('overview')

const options = [
  { label: 'Overview', value: 'overview' },
  { label: 'Account', value: 'account' },
  { disabled: true, label: 'Settings', value: 'settings' },
]
</script>

<template>
  <PTabs v-model="value" variant="segmented" :options="options">
    <template #item="{ option }">
      This is {{ option.value }} tab content.
    </template>
  </PTabs>
</template>

Keep alive

Each panel is mounted the first time its tab becomes active and is then kept alive, so switching tabs no longer discards the state inside it.

<script setup lang="ts">
import { ref } from 'vue'

const value = ref('profile')
const profileName = ref('')
const securityCode = ref('')

const options = [
  { label: 'Profile', value: 'profile' },
  { label: 'Security', value: 'security' },
]
</script>

<template>
  <PTabs v-model="value" keep-alive :options="options">
    <template #item="{ option }">
      <PInput
        v-if="option.value === 'profile'"
        v-model="profileName"
        placeholder="Type in profile tab"
      />
      <PInput v-else v-model="securityCode" placeholder="Type in security tab" />
    </template>
  </PTabs>
</template>

Uncontrolled

Without v-model the tabs keep their own state, and default-value picks the tab shown first.

<script setup lang="ts">
import { ref } from 'vue'

const profileName = ref('')

const options = [
  { label: 'Profile', value: 'profile' },
  { label: 'Security', value: 'security' },
]
</script>

<template>
  <PTabs default-value="profile" :options="options">
    <template #item="{ option }">
      <PInput
        v-if="option.value === 'profile'"
        v-model="profileName"
        placeholder="Type in profile tab"
      />
      <PInput v-else placeholder="This tab is discarded when you switch away." />
    </template>
  </PTabs>
</template>

Props

NameTypeDefaultDescription
variant'default' | 'secondary' | 'segmented'defaultVisual style of the tab bar
keep-aliveboolean-Mount every panel on its first activation and keep it alive afterwards, so its state survives switching
model-valuestring | number-Value of the active tab; binds the component in controlled mode
default-valuestring | number-Tab selected before the consumer binds v-model
optionsComponentOption[][]Tabs to render; each entry is { label, value, disabled? } and value must be unique

Events

NameTypeDescription
change(value: string | number) => voidEmitted once when a tab becomes active through a click or a keyboard command.
update:modelValue(value: string | number) => voidEmitted together with change in controlled mode.

Slots

NameScopeDescription
item{ option, active }Content of the panel, rendered while the tab is active
label{ option, active }Replaces the label text of the tab trigger

Source

Source