Vitral 0.2
Menu

Sidebar

The collapsible application sidebar: navigation with sub-lists, that shrinks to its icons and becomes a drawer on small screens.

Import

main.ts
import { Sidebar } from '@vitral/vue';

Collapsible to icons

Acme Inc.
Page: home
<script setup lang="ts">import { Avatar, Sidebar, type MenuItem } from '@vitral/vue';import { ref } from 'vue'; const active = ref('home');const go = (key: string) => () => (active.value = key);const items: MenuItem[] = [    { label: 'Home', key: 'home', icon: 'home', command: go('home') },    { label: 'Inbox', key: 'inbox', icon: 'bell', command: go('inbox') },    {        label: 'Workspace',        items: [            { label: 'Projects', key: 'projects', icon: 'folder', items: [{ label: 'Vitral', key: 'vitral', command: go('vitral') }, { label: 'Website', key: 'site', command: go('site') }] },            { label: 'Calendar', key: 'calendar', icon: 'calendar', command: go('calendar') },            { label: 'Reports', key: 'reports', icon: 'file', command: go('reports') }        ]    },    { label: 'Settings', items: [{ label: 'Preferences', key: 'prefs', icon: 'sliders', command: go('prefs') }] }]; const collapsed = ref(false);</script> <template>    <div style="display: flex; height: 26rem; width: 100%; border: 1px solid var(--vt-content-border-color); border-radius: 8px; overflow: hidden">        <Sidebar v-model:collapsed="collapsed" :model="items" :active-key="active">            <template #header="{ collapsed: small }">                <strong>{{ small ? 'A' : 'Acme Inc.' }}</strong>            </template>            <template #footer>                <div style="display: flex; align-items: center; gap: 0.5rem">                    <Avatar label="GW" shape="circle" />                    <span>Gustavo</span>                </div>            </template>        </Sidebar>        <main style="flex: 1; padding: 1rem">Page: {{ active }}</main>    </div></template>

Off canvas

<script setup lang="ts">import { Button, Sidebar, type MenuItem } from '@vitral/vue';import { ref } from 'vue'; const active = ref('home');const go = (key: string) => () => (active.value = key);const items: MenuItem[] = [    { label: 'Home', key: 'home', icon: 'home', command: go('home') },    { label: 'Inbox', key: 'inbox', icon: 'bell', command: go('inbox') },    {        label: 'Workspace',        items: [            { label: 'Projects', key: 'projects', icon: 'folder', items: [{ label: 'Vitral', key: 'vitral', command: go('vitral') }, { label: 'Website', key: 'site', command: go('site') }] },            { label: 'Calendar', key: 'calendar', icon: 'calendar', command: go('calendar') },            { label: 'Reports', key: 'reports', icon: 'file', command: go('reports') }        ]    },    { label: 'Settings', items: [{ label: 'Preferences', key: 'prefs', icon: 'sliders', command: go('prefs') }] }]; const hidden = ref(false);</script> <template>    <div style="display: flex; height: 18rem; width: 100%; border: 1px solid var(--vt-content-border-color); border-radius: 8px; overflow: hidden">        <Sidebar v-model:collapsed="hidden" :model="items" :active-key="active" collapsible="offcanvas" aria-label="Main navigation" />        <div style="flex: 1; padding: 1rem">            <Button :label="hidden ? 'Show sidebar' : 'Hide sidebar'" icon="sidebar" severity="secondary" :aria-expanded="!hidden" @click="hidden = !hidden" />        </div>    </div></template>

API

Read from packages/vue/src/components/Sidebar/types.ts, so it says what the component actually accepts.

Props

NameTypeDescription
modelMenuItem[]The navigation. A top-level item with `items` is a labelled group; an item with `items` inside a group opens a sub-list in place. Items are links (`url`) or buttons (`command`).
collapsible'icon' | 'offcanvas' | 'none'How it collapses: to its icons (the default), off the canvas entirely, or not at all.
side'left' | 'right'Which edge it sits on. Defaults to `'left'`.
activeKeystringThe key of the item for the current page; it is marked `aria-current="page"`. Items with `active` are marked too.
mobileBreakpointstringBelow this width it becomes a drawer opened with `v-model:visible`. Defaults to `'768px'`.
showTogglebooleanShow the collapse button in the header. Defaults to true.
ariaLabelstringNames the navigation. Defaults to the locale's "Navigation".

Plus pt, dt and unstyled from BaseProps, see pass-through and unstyled mode.

Emits

EventPayloadDescription
item-clickevent: { originalEvent: Event; item: MenuItem }—

Slots

NameSlot propsDescription
header(props: { collapsed: boolean })Above the navigation: a logo, a workspace switcher.
footer(props: { collapsed: boolean })Below it: the signed-in user.
default(props: { collapsed: boolean })More content after the model's groups.
item(props: { item: MenuItem; collapsed: boolean; active: boolean })An item's content.