Sidebar

Provides a vertical navigation panel for organizing links and actions. Supports sections, collapsible groups, and quick access to key features.

Default

Views

vue
<script setup lang="ts">
import { reactive } from 'vue'
import { Sidebar } from 'frappe-ui'

function toggleTheme() {
  const currentTheme = document.documentElement.getAttribute('data-theme')
  const newTheme = currentTheme === 'dark' ? 'light' : 'dark'
  document.documentElement.setAttribute('data-theme', newTheme)
}

const crmSidebar = reactive({
  header: {
    title: 'Frappe CRM',
    subtitle: 'Jane Doe',
    logo: 'https://raw.githubusercontent.com/frappe/crm/develop/.github/logo.svg',
    menuItems: [
      { label: 'Toggle Theme', icon: 'lucide-moon', onClick: toggleTheme },
      {
        label: 'Help',
        to: '/help',
        icon: 'lucide-settings',
        onClick: () => alert('Help clicked!'),
      },
      {
        label: 'Logout',
        to: '/logout',
        icon: 'lucide-user',
        onClick: () => alert('Logging out...'),
      },
    ],
  },
  sections: [
    {
      label: '',
      items: [{ label: 'Notifications', icon: 'lucide-bell', to: '' }],
    },
    {
      label: '',
      items: [
        { label: 'Leads', icon: 'lucide-users', to: '' },
        { label: 'Deals', icon: 'lucide-briefcase', to: '' },
        { label: 'Contacts', icon: 'lucide-user-check', to: '' },
        { label: 'Organizations', icon: 'lucide-building', to: '' },
        { label: 'Notes', icon: 'lucide-clipboard', to: '' },
        { label: 'Tasks', icon: 'lucide-check-square', to: '' },
        { label: 'Call Logs', icon: 'lucide-phone', to: '' },
        {
          label: 'Email Templates',
          icon: 'lucide-mail',
          to: '',
        },
      ],
    },
    {
      label: 'Views',
      collapsible: true,
      items: [
        { label: 'My Open Deals', icon: 'lucide-link', to: '' },
        { label: 'Partnership Deals', icon: 'lucide-link', to: '' },
        { label: 'Unassigned Deals', icon: 'lucide-link', to: '' },
        {
          label: 'Enterprise Pipeline',
          icon: 'lucide-link',
          to: '',
        },
      ],
    },
  ],
})
</script>

<template>
  <div class="w-full !-m-8">
    <Sidebar :header="crmSidebar.header" :sections="crmSidebar.sections" />
  </div>
</template>

API Reference

Show types
typescript
import type { ComputedRef, InjectionKey, MaybeRefOrGetter } from 'vue'
import { RouteLocationRaw } from 'vue-router'

export const sidebarCollapsedKey: InjectionKey<ComputedRef<boolean>> =
  Symbol('sidebarCollapsed')

export type SidebarHeaderProps = {
  title: string
  subtitle?: string
  logo?: any // Icon component or image string
  menuItems?: {
    label: string
    icon: any // Icon component
    onClick?: () => void
  }[]
}

export type SidebarItemProps = {
  label: string
  accessKey?: string
  icon?: any // Icon component
  suffix?: string
  to?: RouteLocationRaw
  isActive?: boolean
  onClick?: () => void
  condition?: MaybeRefOrGetter<boolean>
}

export type SidebarSectionProps = {
  label?: string
  items: SidebarItemProps[]
  collapsible?: boolean
}

export type SidebarProps = {
  header?: SidebarHeaderProps
  sections?: SidebarSectionProps[]
  disableCollapse?: boolean
}
header
SidebarHeaderProps
sections
SidebarSectionProps[]
disableCollapse
boolean
collapsed
= null
boolean
header
{}
header-logo
{}
sidebar-item
{ item: SidebarItemProps; isCollapsed: false; }
footer-items
{ isCollapsed: boolean; isMobile: boolean; }
update:collapsed
[value: boolean]

Fired when the collapsed changes.

SidebarHeader

Show types
typescript
import type { ComputedRef, InjectionKey, MaybeRefOrGetter } from 'vue'
import { RouteLocationRaw } from 'vue-router'

export const sidebarCollapsedKey: InjectionKey<ComputedRef<boolean>> =
  Symbol('sidebarCollapsed')

export type SidebarHeaderProps = {
  title: string
  subtitle?: string
  logo?: any // Icon component or image string
  menuItems?: {
    label: string
    icon: any // Icon component
    onClick?: () => void
  }[]
}

export type SidebarItemProps = {
  label: string
  accessKey?: string
  icon?: any // Icon component
  suffix?: string
  to?: RouteLocationRaw
  isActive?: boolean
  onClick?: () => void
  condition?: MaybeRefOrGetter<boolean>
}

export type SidebarSectionProps = {
  label?: string
  items: SidebarItemProps[]
  collapsible?: boolean
}

export type SidebarProps = {
  header?: SidebarHeaderProps
  sections?: SidebarSectionProps[]
  disableCollapse?: boolean
}
title*
string
subtitle
string
logo
any
menuItems
{ label: string; icon: any; onClick?: (() => void); }[] | undefined
logo
{}

SidebarItem

Show types
typescript
import type { ComputedRef, InjectionKey, MaybeRefOrGetter } from 'vue'
import { RouteLocationRaw } from 'vue-router'

export const sidebarCollapsedKey: InjectionKey<ComputedRef<boolean>> =
  Symbol('sidebarCollapsed')

export type SidebarHeaderProps = {
  title: string
  subtitle?: string
  logo?: any // Icon component or image string
  menuItems?: {
    label: string
    icon: any // Icon component
    onClick?: () => void
  }[]
}

export type SidebarItemProps = {
  label: string
  accessKey?: string
  icon?: any // Icon component
  suffix?: string
  to?: RouteLocationRaw
  isActive?: boolean
  onClick?: () => void
  condition?: MaybeRefOrGetter<boolean>
}

export type SidebarSectionProps = {
  label?: string
  items: SidebarItemProps[]
  collapsible?: boolean
}

export type SidebarProps = {
  header?: SidebarHeaderProps
  sections?: SidebarSectionProps[]
  disableCollapse?: boolean
}
label*
string
accessKey
string
icon
any
suffix
string
to
string | kt | Tt
isActive
boolean
onClick
(() => void)
icon
{}
suffix
{}

SidebarSection

Show types
typescript
import type { ComputedRef, InjectionKey, MaybeRefOrGetter } from 'vue'
import { RouteLocationRaw } from 'vue-router'

export const sidebarCollapsedKey: InjectionKey<ComputedRef<boolean>> =
  Symbol('sidebarCollapsed')

export type SidebarHeaderProps = {
  title: string
  subtitle?: string
  logo?: any // Icon component or image string
  menuItems?: {
    label: string
    icon: any // Icon component
    onClick?: () => void
  }[]
}

export type SidebarItemProps = {
  label: string
  accessKey?: string
  icon?: any // Icon component
  suffix?: string
  to?: RouteLocationRaw
  isActive?: boolean
  onClick?: () => void
  condition?: MaybeRefOrGetter<boolean>
}

export type SidebarSectionProps = {
  label?: string
  items: SidebarItemProps[]
  collapsible?: boolean
}

export type SidebarProps = {
  header?: SidebarHeaderProps
  sections?: SidebarSectionProps[]
  disableCollapse?: boolean
}
label
string
items*
SidebarItemProps[]
collapsible
boolean
sidebar-item
{ item: SidebarItemProps; isCollapsed: false; }