Skip to content

Page Layout

To keep consistent branding across our applications, you can build your application shell using

Basic usage

The PageHeader component can be used to display page header title, description, media and actions.

The PageContent can be used to display the main page content.

The PageNavigation is a wrapper component around Tabs that is only used when the tabs are tied to routes, allowing the user to navigate between pages. There's some extra convenience logic that auto selects the active tab based on the current route.

Pricing

Volume Discounts page

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

  import PageContent from '../../../src/components/PageContent/PageContent.vue';
  import PageHeader from '../../../src/components/PageHeader/PageHeader.vue';
  import PageNavigation from '../../../src/components/PageNavigation/PageNavigation.vue';

  const items = ref([
    { label: 'Volume Discounts', value: 'volume-discounts', href: '#basic-usage-volume-discounts' },
    { label: 'Promotions', value: 'promotions', href: '#basic-usage-promotions' },
    { label: 'Custom Menus', value: 'custom-menus', href: '#basic-usage-custom-menus' },
  ]);

  const activeRoute = ref('volume-discounts');
</script>

<template>
  <PageHeader title="Pricing" />

  <PageNavigation v-model="activeRoute" :items="items" />

  <PageContent>
    <div :id="`tabpanel-${activeRoute}`" role="tabpanel">
      <p v-if="activeRoute === items[0].value">Volume Discounts page</p>
      <p v-if="activeRoute === items[1].value">Promotions page</p>
      <p v-if="activeRoute === items[2].value">Custom Menus page</p>
    </div>
  </PageContent>
</template>

Title

The PageHeader component can be used to display a page header title by passing a title prop.

It can be used to display a page header description by passing a description prop.

Page Header Title

A simple page header description

vue
<script setup lang="ts">
  import PageHeader from '../../../src/components/PageHeader/PageHeader.vue';
</script>

<template>
  <PageHeader title="Page Header Title" description="A simple page header description" />
</template>

Media

The PageHeader component can be used to display a page header media by passing a media slot.

Documents

All your historical statements, disclosures, and tax documents

vue
<script setup lang="ts">
  import Illustration from '../../../src/components/Illustration/Illustration.vue';
  import PageHeader from '../../../src/components/PageHeader/PageHeader.vue';
</script>

<template>
  <PageHeader title="Documents" description="All your historical statements, disclosures, and tax documents">
    <template #media>
      <Illustration name="discover" fill-color="ice" :size="58" />
    </template>
  </PageHeader>
</template>

Actions

The PageHeader component can be used to display some page level actions by passing a primary-action slot. It's also possible to pass in a secondary-action slot.

Page Header Title

vue
<script setup lang="ts">
  import Button from '../../../src/components/Button/Button.vue';
  import Icon from '../../../src/components/Icon/Icon.vue';
  import PageHeader from '../../../src/components/PageHeader/PageHeader.vue';
</script>

<template>
  <PageHeader title="Page Header Title">
    <template #primary-action>
      <Button icon>
        <Icon name="plus" />
      </Button>
    </template>
  </PageHeader>
</template>

When the to key is provided, <PageNavigation /> renders a RouterLink internally which allows vue-router to handle navigation.

INFO

Currently, there's no way of passing a vue router instance to vitepress, so the example using a router link wouldn't work in this page. But you can see a working example in the code snippet below.

vue
<script lang="ts">
  const pageState = ref({
    title: 'Pricing',
    description: 'Set up custom menus, volume discounts and promo codes',
    tabs: [
      {
        label: 'Volume Discounts',
        to: '/volume-discounts',
      },
      {
        label: 'Promotions',
        to: '/promotions',
      },
      {
        label: 'Custom Menus',
        to: '/custom-menus',
      },
    ],
  });
</script>

<template>
  <PageHeader :title="pageState.value.title" :description="pageState.value.description" />

  <PageNavigation :items="pageState.value.tabs" />

  <PageContent>
    <router-view v-slot="{ Component }">
      <keep-alive>
        <component :is="Component" />
      </keep-alive>
    </router-view>
  </PageContent>
</template>

When the href key is provided on item, <PageNavigation> renders an <a> internally which allows server-side navigation, such as with legacy Django pages in the Marketplace application.

See this example for more details on how to use it.

You need to provide a tab panel element in order to make the navigation work with an id matching the kebab cased current tab label prefixed by tabpanel-.

html
<div :id="`tabpanel-${activeRoute}`" role="tabpanel">
  <!-- Put your page content here -->
</div>

Disabled item

An item can be disabled with the disabled property.

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

  import PageNavigation from '../../../src/components/PageNavigation/PageNavigation.vue';

  const items = ref([
    { label: 'Volume Discounts', value: 'volume-discounts', href: '#disabled-item-volume-discounts', disabled: true },
    { label: 'Promotions', value: 'promotions', href: '#disabled-item-promotions' },
    { label: 'Custom Menus', value: 'custom-menus', href: '#disabled-item-custom-menus' },
  ]);

  const activeRoute = ref('promotions');
</script>

<template>
  <PageNavigation v-model="activeRoute" :items="items" />
  <div :id="`tabpanel-${activeRoute}`" role="tabpanel"></div>
</template>

Badge item

To display a badge in an item, provide a badge property in the item config. The badge can be used to display extra information, such as the number of pending transactions:

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

  import PageNavigation from '../../../src/components/PageNavigation/PageNavigation.vue';

  const items = ref([
    { label: 'Volume Discounts', value: 'volume-discounts', href: '#badge-item-volume-discounts', badge: 99 },
    { label: 'Promotions', value: 'promotions', href: '#badge-item-promotions' },
    { label: 'Custom Menus', value: 'custom-menus', href: '#badge-item-custom-menus' },
  ]);

  const activeRoute = ref('volume-discounts');
</script>

<template>
  <PageNavigation v-model="activeRoute" :items="items" />
  <div :id="`tabpanel-${activeRoute}`" role="tabpanel"></div>
</template>

More button

The component will automatically show a "More" button if there are too many tabs to fit on the screen.

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

  import PageNavigation from '../../../src/components/PageNavigation/PageNavigation.vue';

  const items = ref([
    {
      label: 'One',
      value: 'one',
      href: '#more-button-one',
    },
    {
      label: 'Two',
      value: 'two',
      href: '#more-button-two',
    },
    {
      label: 'Three',
      value: 'three',
      href: '#more-button-three',
    },
    {
      label: 'Four',
      value: 'four',
      href: '#more-button-four',
    },
    {
      label: 'Five',
      value: 'five',
      href: '#more-button-five',
    },
    {
      label: 'Six',
      value: 'six',
      href: '#more-button-six',
    },
    {
      label: 'Seven',
      value: 'seven',
      href: '#more-button-seven',
    },
    {
      label: 'Eight',
      value: 'eight',
      href: '#more-button-eight',
    },
    {
      label: 'Nine',
      value: 'nine',
      href: '#more-button-nine',
    },
    {
      label: 'Ten',
      value: 'ten',
      href: '#more-button-ten',
    },
    {
      label: 'Eleven',
      value: 'eleven',
      href: '#more-button-eleven',
    },
    {
      label: 'Twelve',
      value: 'twelve',
      href: '#more-button-twelve',
    },
    {
      label: 'Thirteen',
      value: 'thirteen',
      href: '#more-button-thirteen',
      badge: 99,
    },
    {
      label: 'Fourteen',
      value: 'fourteen',
      href: '#more-button-fourteen',
    },
    {
      label: 'Fifteen',
      value: 'fifteen',
      href: '#more-button-fifteen',
      disabled: true,
    },
    {
      label: 'Sixteen',
      value: 'sixteen',
      href: '#more-button-sixteen',
    },
    {
      label: 'Seventeen',
      value: 'seventeen',
      href: '#more-button-seventeen',
    },
    {
      label: 'Eighteen',
      value: 'eighteen',
      href: '#more-button-eighteen',
    },
    {
      label: 'Nineteen',
      value: 'nineteen',
      href: '#more-button-nineteen',
    },
  ]);

  const activeRoute = ref('one');
</script>

<template>
  <PageNavigation v-model="activeRoute" :items="items" />
  <div :id="`tabpanel-${activeRoute}`" role="tabpanel"></div>
</template>

active-index

To control the active tab by its index instead of its value, use the active-index prop.

WARNING

The active-index is deprecated and will be removed in the next major version. Use v-model instead.

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

  import PageNavigation from '../../../src/components/PageNavigation/PageNavigation.vue';

  const items = ref([
    { label: 'Volume Discounts', value: 'volume-discounts', href: '#active-index-volume-discounts' },
    { label: 'Promotions', value: 'promotions', href: '#active-index-promotions' },
    { label: 'Custom Menus', value: 'custom-menus', href: '#active-index-custom-menus' },
  ]);

  const activeRouteIndex = ref(2);
  const activeRoute = ref('');
</script>

<template>
  <PageNavigation
    v-model="activeRoute"
    :items="items"
    :active-index="activeRouteIndex"
    @change="activeRouteIndex = $event"
  />
  <div :id="`tabpanel-${activeRoute}`" role="tabpanel"></div>
</template>

Page Content

If the PageContent sidebar slot is used, the component will adjust its layout to accommodate the sidebar content.

Main content

Modernipsum dolor sit amet color field painting cobra art deco, social realism photorealism orphism neoclassicism. Synthetism perspectivism les nabis academic carolingian new objectivity outsider art secularism academic tachism, eclecticism socialist realism secularism tachisme international gothic neue slowenische kunst kinetic art sound art. Russian futurism precisionism gothic art neo-impressionism barbizon school divisionism naturalism lettrism, baroque mail art street art international gothic socialist realism.
vue
<script setup lang="ts">
  import PageContent from '../../../src/components/PageContent/PageContent.vue';
  import TextBlock from './TextBlock.vue';
</script>

<template>
  <PageContent>
    <h2>Main content</h2>
    <TextBlock />

    <template #sidebar>
      <h2>Sidebar</h2>
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
      </ul>
    </template>
  </PageContent>
</template>

API

See the documentation below for a complete reference to all the props and classes available to the components mentioned here.