Skip to content

SidebarLayout

A responsive two-panel layout with a collapsible sidebar and main content area. On mobile, the sidebar becomes an overlay.

Demo

Open in full window ↗

Tabs Demo (Router Mode)

Open in full window ↗

Usage

vue
<SidebarLayout>
  <template #sidebar>
    <h2>Controls</h2>
    <NumberInput v-model="value" label="Parameter" slider live />
  </template>
  <h1>Main Content</h1>
  <p>Your charts and data go here.</p>
</SidebarLayout>

Slots

SlotDescription
sidebarContent rendered in the left sidebar panel
defaultMain content area

Props

PropTypeDefaultDescription
hideTopbarbooleanfalseHides the topbar that contains the light/dark toggle
tabsTab[]undefinedArray of tab definitions to render in the main area
v-model:tabstringundefinedThe active tab value (two-way binding)

Tab type

ts
interface Tab {
  value: string; // unique identifier
  label: string; // display text
  to?: string; // optional route path for vue-router integration
}

Tabs

When the tabs prop is provided, a tab bar renders at the top of the main content area. Tabs support two modes:

Local mode

Use v-model:tab to control which tab is active. Render content conditionally in the default slot.

vue
<script setup>
import { ref } from "vue";
const activeTab = ref("chart");
</script>

<SidebarLayout
  v-model:tab="activeTab"
  :tabs="[
    { value: 'chart', label: 'Chart' },
    { value: 'data', label: 'Data' },
  ]"
>
  <template #sidebar>
    <h2>Controls</h2>
  </template>
  <div v-if="activeTab === 'chart'">Chart content</div>
  <div v-if="activeTab === 'data'">Data table</div>
</SidebarLayout>

Router mode

When tabs include a to property and vue-router is installed, clicking a tab navigates to that route. The active tab is automatically determined from the current route.

vue
<SidebarLayout
  :tabs="[
    { value: 'chart', label: 'Chart', to: '/model/chart' },
    { value: 'data', label: 'Data', to: '/model/data' },
  ]"
>
  <template #sidebar>
    <h2>Controls</h2>
  </template>
  <RouterView />
</SidebarLayout>