Sidebar

A collapsible, resizable application sidebar with header/footer slots, a drag-to-resize edge and a collapse toggle in its header.

vue
<UiSidebar />

Options

One block per prop — what it does, and what it looks like set.

Collapsible

collapsible is how the sidebar gets out of the way. Its default, icon, shrinks it to an icon-only strip that still navigates; offcanvas hides it altogether; none fixes it open and drops the toggle entirely. The header, default and footer slots are all handed the current state, which is how the content below knows to render labels or not — click the toggle in the header, or drag the edge, to see it.

JD
Jane Doe
Admin

Side

side moves the sidebar to the other edge of the screen. The header toggle's icon, the resize handle and the collapse direction all mirror along with it.

Resizable

resizable puts a ResizeHandle down the full height of the sidebar's edge, so a width drag can start anywhere along it. Off, the sidebar keeps exactly the widths you gave it — defaultWidth expanded, the icon strip collapsed — which is what the sidebar below does.

Dragging past minWidth snaps the sidebar collapsed rather than clamping, and dragging back out of a collapsed one re-expands it at minWidth. Both trigger halfway across the gap between the two widths (capped at 60px), so the edge lands as near your pointer as a jump that size allows, and both directions cost the same — the handle re-anchors to the pointer as a snap lands, which is the hysteresis. Collapsing animates; expanding yields to your pointer the moment you keep dragging. All of it rides on the handle's overdrag event: nothing in ResizeHandle knows what collapsing means.

Open

open takes the expanded/collapsed state out of the sidebar's hands. Bind it with v-model:open so the header toggle still works, or turn the built-in controls off and drive it entirely from elsewhere — which is the pairing below: close is false, and a SidebarToggle sitting outside the sidebar shares the same ref. Same component the header renders, just somewhere else.

Default open

defaultOpen decides whether an uncontrolled sidebar starts expanded. It's true by default; set it false for a shell where the content is the point and the navigation is something you go looking for. Once the reader touches the toggle the sidebar owns the state, so this only ever describes the first render.

Title

title is the name in the built-in header, shown instead of the default logo. It's ignored the moment you provide a header slot, which replaces that whole area — reach for the prop when a line of text is all you need, and the slot when the header has to hold a team switcher.

Bundy

Workspace

Description

description is the quieter second line under the title — the workspace, the environment, whatever qualifies the name above it. Both collapse away with the sidebar. The title and description slots below keep this header layout while replacing just the text, which is the middle ground between the props and the full header slot.

Bundy Pro

All systems normal

Close

close is the SidebarToggle in the header, and it's on by default — it's the sidebar's only built-in way to collapse and expand. Turn it off and the sidebar can still be driven through v-model:open from a control of your own. It does nothing at all when collapsible is none, since there's then nothing to collapse to.

Bundy

Workspace

Collapsing and resizing are two separate controls in two separate places: close is the SidebarToggle in the header, resizable the full-height ResizeHandle on the edge. Either can be turned off without losing the other. The rail slot replaces what sits on the edge — it's handed state and open, so a replacement can render whatever it likes out there.

Default width

defaultWidth is the pixel width the sidebar opens at. It's a starting point rather than a fixed size — the resize handle drags it anywhere between minWidth and maxWidth from there, and a double-click on the handle puts it back.

Min width

minWidth is how narrow the resize handle can drag the sidebar. Set it to the width your narrowest label still fits in — dragging further doesn't squeeze past it, and pushing well beyond the bound snaps the sidebar collapsed instead, so the reader gets the icon strip rather than a cramped one.

Max width

maxWidth is the other bound — how wide the resize handle can pull the sidebar before it stops. Keep it modest: past a point the sidebar is just taking room from the content, and dragging hard past the bound only stops, rather than growing further.


Examples

The component in real use: compositions that answer "how do I build X with this", rather than one prop at a time.

`collapsible="none"` — pinned open, so no toggle is rendered at all

`collapsible="offcanvas"` — hides the sidebar completely instead of shrinking it to icons

Nested sub-items — children collapse away with the sidebar, since there's no room for them at icon width

items isn't a prop — the sidebar owns layout only; navigation content is entirely up to the consumer via the default slot, matching NuxtUI's separation of concerns.

The sidebar this app's own dashboard renders — a full composition, not a prop demo

Source: app/components/examples/DashboardSidebar.vue.

The sidebar has no height of its own — calc(100vh - 24px) is a *max*, not a fill. Its inner column is h-full, a percentage that resolves to auto unless an ancestor has a definite height, so on its own it sizes to its content. Put it in a stretching parent (<div class="flex min-h-screen">, as this app's layout does) to get a full-height app rail; the footer only pins to the bottom once something gives it height.


API Reference

Generated from the component's source — props, slots and emits as the component actually declares them.

Props

Prop
Type
Default
Description
"offcanvas" | "icon" | "none"
'icon'
The collapse behavior of the sidebar. - `icon`: shrinks to icon-only width. - `offcanvas`: hides completely. - `none`: not collapsible; the header toggle is never shown.
"left" | "right"
'left'
The side to render the sidebar on.
boolean
true
Display a `ResizeHandle` down the sidebar edge to drag its width. Independent of `close` — turn this off for a sidebar that still collapses but always to the same width.
boolean
—
Controls whether the sidebar is expanded. Omit this to let the sidebar manage its own state internally (starting from `defaultOpen`); pass it to fully control it yourself.
boolean
true
Whether the sidebar starts expanded when uncontrolled.
string
—
Title displayed in the header. Ignored when the `header` slot is used.
string
—
Description displayed below the title. Ignored when the `header` slot is used.
boolean
true
Shows a `SidebarToggle` in the header that collapses and expands the sidebar. It's the only built-in control for that, so turning it off means supplying your own via `v-model:open`. Has no effect when `collapsible` is `none`, since there's nothing to collapse to.
number
208
The width, in pixels, the sidebar starts at when expanded. Draggable via the resize handle, and what double-clicking the handle restores.
number
180
The minimum width, in pixels, the resize handle can drag the sidebar down to.
number
400
The maximum width, in pixels, the resize handle can drag the sidebar up to.

Slots

Slot
header
Receives `{ state, open }`.
title
Receives `{ state }`.
description
Receives `{ state }`.
default
Receives `{ state, open }`.
footer
Receives `{ state, open }`.
rail
Receives `{ state, open }`.

Emits

Event
Payload
Description
update:open
[value: boolean]
—

Types

ts
type SidebarState = "expanded" | "collapsed";