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
<script setup lang="ts">
import { ref } from 'vue';
import Module from '../../../src/components/Module/Module.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 :active-tab="activeRoute">
<Module v-if="activeRoute === items[0].value">Volume Discounts page</Module>
<Module v-if="activeRoute === items[1].value">Promotions page</Module>
<Module v-if="activeRoute === items[2].value">Custom Menus page</Module>
</PageContent>
</template>
Page Header
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
<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
<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
<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>
Page Navigation
Router-link
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.
<script lang="ts">
const route = useRoute();
const pageState = ref({
title: 'Pricing',
description: 'Set up custom menus, volume discounts and promo codes',
tabs: [
{
value: 'volume-discounts'
label: 'Volume Discounts',
to: '/volume-discounts',
},
{
value: 'promotions'
label: 'Promotions',
to: '/promotions',
},
{
value: 'custom-menus',
label: 'Custom Menus',
to: '/custom-menus',
},
],
});
const activeTab = computed(() => {
return pageState.tabs.find((tab) => route.path.includes(tab.to));
});
</script>
<template>
<PageHeader :title="pageState.value.title" :description="pageState.value.description" />
<PageNavigation :model-value="pageState.value.activeTab" :items="pageState.value.tabs" />
<PageContent :active-tab="pageState.value.activeTab">
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
</PageContent>
</template>
Anchor and Hyperlinks Navigation
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.
Disabled item
An item
can be disabled with the disabled
property.
<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:
<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.
<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.
<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
Active Tab
PageContent can receive an active-tab
prop that is intended to work with <PageNavigation>
. When provided, PageContent will render role="tabpanel"
and an id
that matches PageNavigation's model-value
prop; this improves accessibility and SEO for the tab components rendered within PageNavigation so that screen readers and search engines know to associate each tab with its content.
<PageNavigation v-model="activeTab" :items="tabs" />
<PageContent :active-tab="activeTab">
<!-- content -->
</PageContent>
If the active-tab
prop is not provided, the id
and role
attributes be be undefined
by default.
Sidebar
If the PageContent
sidebar slot is used, the component will adjust its layout to accommodate the sidebar content.
<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.