DashboardSidebar

A resizable and collapsible sidebar to display in a dashboard.

Usage

The DashboardSidebar component is used to display a sidebar. Its state (size, collapsed, etc.) will be saved based on the storage and storage-key props you provide to the DashboardGroup component.

Use it inside the default slot of the DashboardGroup component:

layouts/dashboard.vue
<template>
  <UDashboardGroup>
    <UDashboardSidebar />

    <slot />
  </UDashboardGroup>
</template>

Use the left, default and right slots to customize the sidebar and the body or content slots to customize the sidebar menu.

<script setup lang="ts">
const links = [[{
  label: 'Home',
  icon: 'i-lucide-house',
  active: true
}, {
  label: 'Inbox',
  icon: 'i-lucide-inbox',
  badge: '4'
}, {
  label: 'Contacts',
  icon: 'i-lucide-users'
}, {
  label: 'Settings',
  icon: 'i-lucide-settings',
  defaultOpen: true,
  children: [{
    label: 'General'
  }, {
    label: 'Members'
  }, {
    label: 'Notifications'
  }]
}], [{
  label: 'Feedback',
  icon: 'i-lucide-message-circle',
  to: 'https://github.com/nuxt-ui-pro/dashboard',
  target: '_blank'
}, {
  label: 'Help & Support',
  icon: 'i-lucide-info',
  to: 'https://github.com/nuxt/ui-pro',
  target: '_blank'
}]]
</script>

<template>
  <UDashboardSidebar collapsible resizable :ui="{ footer: 'border-t border-(--ui-border)' }">
    <template #header="{ collapsed }">
      <LogoPro :collapsed="collapsed" class="h-5 w-auto shrink-0" />
    </template>

    <template #default="{ collapsed }">
      <UButton
        :label="collapsed ? undefined : 'Search...'"
        icon="i-lucide-search"
        color="neutral"
        variant="outline"
        block
        :square="collapsed"
      >
        <template v-if="!collapsed" #trailing>
          <div class="flex items-center gap-0.5 ms-auto">
            <UKbd value="meta" variant="subtle" />
            <UKbd value="K" variant="subtle" />
          </div>
        </template>
      </UButton>

      <UNavigationMenu
        :collapsed="collapsed"
        :items="links[0]"
        orientation="vertical"
      />

      <UNavigationMenu
        :collapsed="collapsed"
        :items="links[1]"
        orientation="vertical"
        class="mt-auto"
      />
    </template>

    <template #footer="{ collapsed }">
      <UButton
        :avatar="{
          src: 'https://github.com/benjamincanac.png'
        }"
        :label="collapsed ? undefined : 'Benjamin'"
        color="neutral"
        variant="ghost"
        class="w-full"
        :block="collapsed"
      />
    </template>
  </UDashboardSidebar>
</template>
Drag the sidebar near the left edge of the screen to collapse it.

Resizable

Use the resizable prop to make the sidebar resizable.

<template>
  <UDashboardSidebar resizable>
    <Placeholder class="h-96" />
  </UDashboardSidebar>
</template>

Collapsible

Use the collapsible prop to make the sidebar collapsible when dragging near the edge of the screen.

The DashboardSidebarCollapse component will have no effect if the sidebar is not collapsible.
<template>
  <UDashboardSidebar resizable collapsible>
    <Placeholder class="h-96" />
  </UDashboardSidebar>
</template>
You can access the collapsed state in the slot props to customize the content of the sidebar when it is collapsed.

Size

Use the min-size, max-size, default-size and collapsed-size props to customize the size of the sidebar.

<template>
  <UDashboardSidebar
    resizable
    collapsible
    :min-size="22"
    :default-size="35"
    :max-size="40"
    :collapsed-size="0"
  >
    <Placeholder class="h-96" />
  </UDashboardSidebar>
</template>
The collapsed-size prop is set to 0 by default but the sidebar has a min-w-16 to make sure it is visible.

Mode

Use the mode prop to change the mode of the sidebar menu. Defaults to slideover.

Use the body slot to fill the menu body (under the header) or the content slot to fill the entire menu.

You can use the menu prop to customize the menu of the sidebar, it will adapt depending on the mode you choose.
<script setup lang="ts">
defineProps<{
  mode: 'drawer' | 'slideover' | 'modal'
}>()

const links = [{
  label: 'Home',
  icon: 'i-lucide-house',
  active: true
}, {
  label: 'Inbox',
  icon: 'i-lucide-inbox'
}, {
  label: 'Contacts',
  icon: 'i-lucide-users'
}]
</script>

<template>
  <UDashboardGroup>
    <UDashboardSidebar :mode="mode">
      <template #header>
        <LogoPro class="h-5 w-auto" />
      </template>

      <UNavigationMenu
        :items="links"
        orientation="vertical"
      />
    </UDashboardSidebar>

    <UDashboardPanel>
      <template #header>
        <UDashboardNavbar title="Dashboard" />
      </template>
    </UDashboardPanel>
  </UDashboardGroup>
</template>
These examples contain the DashboardGroup, DashboardPanel and DashboardNavbar components as they are required to demonstrate the sidebar on mobile.

Toggle

Use the toggle prop to customize the DashboardSidebarToggle component displayed on mobile.

You can pass any property from the Button component to customize it.

<script setup lang="ts">
const links = [{
  label: 'Home',
  icon: 'i-lucide-house',
  active: true
}, {
  label: 'Inbox',
  icon: 'i-lucide-inbox'
}, {
  label: 'Contacts',
  icon: 'i-lucide-users'
}]
</script>

<template>
  <UDashboardGroup>
    <UDashboardSidebar
      open
      :toggle="{
        color: 'primary',
        variant: 'subtle',
        class: 'rounded-full'
      }"
    >
      <template #header>
        <LogoPro class="h-5 w-auto" />
      </template>

      <UNavigationMenu
        :items="links"
        orientation="vertical"
      />
    </UDashboardSidebar>

    <UDashboardPanel>
      <template #header>
        <UDashboardNavbar title="Dashboard" />
      </template>
    </UDashboardPanel>
  </UDashboardGroup>
</template>

Toggle Side

Use the toggle-side prop to change the side of the toggle button. Defaults to left.

<script setup lang="ts">
const links = [{
  label: 'Home',
  icon: 'i-lucide-house',
  active: true
}, {
  label: 'Inbox',
  icon: 'i-lucide-inbox'
}, {
  label: 'Contacts',
  icon: 'i-lucide-users'
}]
</script>

<template>
  <UDashboardGroup>
    <UDashboardSidebar
      open
      toggle-side="right"
    >
      <template #header>
        <LogoPro class="h-5 w-auto" />
      </template>

      <UNavigationMenu
        :items="links"
        orientation="vertical"
      />
    </UDashboardSidebar>

    <UDashboardPanel>
      <template #header>
        <UDashboardNavbar title="Dashboard" />
      </template>
    </UDashboardPanel>
  </UDashboardGroup>
</template>

Examples

Control open state

You can control the open state by using the open prop or the v-model:open directive.

<script setup lang="ts">
const links = [{
  label: 'Home',
  icon: 'i-lucide-house',
  active: true
}, {
  label: 'Inbox',
  icon: 'i-lucide-inbox'
}, {
  label: 'Contacts',
  icon: 'i-lucide-users'
}]

const open = ref(true)

defineShortcuts({
  o: () => open.value = !open.value
})
</script>

<template>
  <UDashboardSidebar v-model:open="open">
    <template #header>
      <LogoPro class="h-5 w-auto" />
    </template>

    <UNavigationMenu
      :items="links"
      orientation="vertical"
    />
  </UDashboardSidebar>
</template>
In this example, leveraging defineShortcuts, you can toggle the open state of the DashboardSidebar by pressing O.

Control collapsed state

You can control the collapsed state by using the collapsed prop or the v-model:collapsed directive.

<script setup lang="ts">
const links = [{
  label: 'Home',
  icon: 'i-lucide-house',
  active: true
}, {
  label: 'Inbox',
  icon: 'i-lucide-inbox'
}, {
  label: 'Contacts',
  icon: 'i-lucide-users'
}]

const collapsed = ref(false)

defineShortcuts({
  c: () => collapsed.value = !collapsed.value
})
</script>

<template>
  <UDashboardSidebar v-model:collapsed="collapsed" collapsible>
    <template #header>
      <LogoPro class="h-5 w-auto" :collapsed="collapsed" />
    </template>

    <UNavigationMenu
      :collapsed="collapsed"
      :items="links"
      orientation="vertical"
    />
  </UDashboardSidebar>
</template>
In this example, leveraging defineShortcuts, you can toggle the collapsed state of the DashboardSidebar by pressing C.

API

Props

Prop Default Type
open

boolean

collapsed

boolean

mode

'slideover'

"modal" | "slideover" | "drawer"

The mode of the sidebar menu.

menu

DrawerProps | ModalProps | SlideoverProps

The props for the sidebar menu component.

toggle

true

boolean | ButtonProps

Customize the toggle button to open the sidebar. { color: 'neutral', variant: 'ghost' }

toggleSide

'left'

"left" | "right"

The side to render the toggle button on.

collapsible

false

boolean

Whether to allow the user to collapse the panel.

id

useId()

string

The id of the panel.

maxSize

20

number

The maximum size of the panel.

minSize

10

number

The minimum size of the panel.

collapsedSize

0

number

The size of the panel when collapsed.

defaultSize

15

number

The default size of the panel.

resizable

false

boolean

Whether to allow the user to resize the panel.

ui

Partial<{ root: string; header: string; body: string; footer: string; toggle: string; handle: string; content: string; overlay: string; }>

Slots

Slot Type
header

{ collapsed?: boolean | undefined; collapse?: ((value: boolean) => void) | undefined; }

default

{ collapsed?: boolean | undefined; collapse?: ((value: boolean) => void) | undefined; }

footer

{ collapsed?: boolean | undefined; collapse?: ((value: boolean) => void) | undefined; }

toggle

{ open: boolean; toggle: () => void; }

content

{}

resize-handle

{ onMouseDown: (e: MouseEvent) => void; onTouchStart: (e: TouchEvent) => void; }

Theme

app.config.ts
export default defineAppConfig({
  uiPro: {
    dashboardSidebar: {
      slots: {
        root: 'hidden lg:flex flex-col min-h-svh min-w-16 w-(--width) border-r border-(--ui-border) shrink-0',
        header: 'h-(--ui-header-height) shrink-0 flex items-center gap-1.5 px-4',
        body: 'flex flex-col gap-4 flex-1 overflow-y-auto px-4 py-2',
        footer: 'shrink-0 flex items-center gap-1.5 px-4 py-2',
        toggle: '',
        handle: '',
        content: 'lg:hidden',
        overlay: 'lg:hidden'
      },
      variants: {
        menu: {
          true: {
            header: 'sm:px-6',
            body: 'sm:px-6',
            footer: 'sm:px-6'
          }
        },
        toggleSide: {
          left: {
            toggle: ''
          },
          right: {
            toggle: 'ms-auto'
          }
        }
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      uiPro: {
        dashboardSidebar: {
          slots: {
            root: 'hidden lg:flex flex-col min-h-svh min-w-16 w-(--width) border-r border-(--ui-border) shrink-0',
            header: 'h-(--ui-header-height) shrink-0 flex items-center gap-1.5 px-4',
            body: 'flex flex-col gap-4 flex-1 overflow-y-auto px-4 py-2',
            footer: 'shrink-0 flex items-center gap-1.5 px-4 py-2',
            toggle: '',
            handle: '',
            content: 'lg:hidden',
            overlay: 'lg:hidden'
          },
          variants: {
            menu: {
              true: {
                header: 'sm:px-6',
                body: 'sm:px-6',
                footer: 'sm:px-6'
              }
            },
            toggleSide: {
              left: {
                toggle: ''
              },
              right: {
                toggle: 'ms-auto'
              }
            }
          }
        }
      }
    })
  ]
})