Components

Sidebar

Responsive application sidebar with desktop collapse, resizing, and mobile dialog behavior.

Sidebar renders persistent navigation on desktop and reuses modal Drawer behavior on small screens. Content stays consumer-owned while Akaza UI manages responsive state, collapse geometry, resizing, focus, dismissal, and accessibility.

Anatomy

  • #header: Fixed region for branding, workspace controls, or an internal collapse action.
  • #default: Scrollable navigation or application content.
  • #footer: Fixed region for account controls or secondary actions.
  • #resize-handle: Optional content inside the generated accessible resize separator.

Every slot receives responsive state, size, and safe action functions. Toggle controls outside the sidebar should use v-model or useSidebar; Akaza does not require a separate trigger sub-component.

Usage

Workspace

Dashboard

Resize the sidebar or reduce the preview width to see mobile modal behavior.

Selected: overview

Examples

Nested navigation

Compose Sidebar with a vertical NavigationMenu for groups, nested items, active state, badges, collapsed tooltips, and side flyouts. The sidebar owns responsive layout; the navigation menu owns navigation state.

akaza-ui

Selected navigation value

Collapse modes

Use icon when compact controls remain usable. Use offcanvas when the complete desktop panel should leave the layout.

<Sidebar v-model:collapsed="collapsed" collapsible="icon" />
<Sidebar v-model:collapsed="hidden" collapsible="offcanvas" />
<Sidebar :collapsible="false" />

In icon mode, slot content remains mounted and interactive. Use the slot's collapsed value to hide labels or replace content. Off-canvas content becomes inert and aria-hidden when collapsed.

Mobile dialog

breakpoint controls when the persistent sidebar becomes a modal drawer. mobile can override media-query detection for container-based layouts or tests.

<script setup lang="ts">
import { ref } from "vue";

const open = ref(false);
</script>

<template>
  <button :aria-expanded="open" @click="open = true">Open navigation</button>

  <Sidebar
    v-model:open="open"
    breakpoint="(max-width: 64rem)"
    side="left"
    aria-label="Main navigation"
  >
    <nav>...</nav>
  </Sidebar>
</template>

Mobile mode traps focus, locks body scrolling, makes the outside tree inert, closes on Escape or backdrop interaction, restores focus, and supports directional swipe dismissal. Activating an unmodified same-window link closes the sidebar by default.

Resizing

Enable the generated separator with resizable. Size uses pixels and supports controlled or uncontrolled state.

<Sidebar
  v-model:size="size"
  resizable
  :default-size="256"
  :min-size="192"
  :max-size="480"
  :resize-step="8"
>
  <template #resize-handle>
    <span aria-hidden="true" />
  </template>
</Sidebar>

The resize handle supports pointer, pen, touch, and keyboard input. Double-click resets to defaultSize.

Placement also changes pointer and keyboard resize direction.

<Sidebar side="right" collapsible="icon" resizable aria-label="Inspector">
  <template #header>Inspector</template>
  Properties
</Sidebar>

Keyboard shortcut

Global shortcuts are opt-in to avoid application conflicts. keyboardShortcut="b" uses Command+B on macOS and Ctrl+B elsewhere.

<Sidebar keyboard-shortcut="b" collapsible="icon" />

Shortcuts are ignored while focus is inside an input, textarea, select, or editable element.

Custom behavior with useSidebar

Pass a component ref when controls live outside a sidebar. Each composable instance controls only the referenced sidebar, so an application can manage multiple sidebars independently.

<script setup lang="ts">
import type { SidebarController } from "akaza-ui";
import { Sidebar, useSidebar } from "akaza-ui";
import { useTemplateRef } from "vue";

const sidebarRef = useTemplateRef<SidebarController>("sidebar");
const sidebar = useSidebar(sidebarRef);
</script>

<template>
  <button type="button" @click="sidebar.toggle()">Toggle navigation</button>
  <Sidebar ref="sidebar" collapsible="icon">...</Sidebar>
</template>

For state owned outside the component, useSidebar({ open, collapsed, breakpoint }) remains available. Persistence and route watching remain application concerns.

useSidebar

useSidebar has two overloads. Pass a Sidebar component ref to control one rendered instance, or pass an options object when the application owns the state.

function useSidebar(target: SidebarTarget): UseSidebarTargetReturn;
function useSidebar(options?: UseSidebarOptions): UseSidebarReturn;

Component ref mode

Use this mode for external controls, multiple sidebars, or access to the rendered sidebar's responsive and size state.

<script setup lang="ts">
import type { SidebarController } from "akaza-ui";
import { Sidebar, useSidebar } from "akaza-ui";
import { useTemplateRef } from "vue";

const primaryRef = useTemplateRef<SidebarController>("primary");
const inspectorRef = useTemplateRef<SidebarController>("inspector");

const primary = useSidebar(primaryRef);
const inspector = useSidebar(inspectorRef);
</script>

<template>
  <button type="button" @click="primary.toggle()">Toggle navigation</button>
  <button type="button" @click="inspector.toggle()">Toggle inspector</button>

  <Sidebar ref="primary" collapsible="icon">...</Sidebar>
  <Sidebar ref="inspector" side="right" collapsible="offcanvas">...</Sidebar>
</template>

Each controller delegates only to its referenced instance. Calls made before that instance mounts are ignored.

Controlled state mode

Use this mode when state must exist before the component mounts or must be shared with storage, routing, or other application logic. Pass the same refs to Sidebar models.

<script setup lang="ts">
import { Sidebar, useSidebar } from "akaza-ui";
import { ref } from "vue";

const open = ref(false);
const collapsed = ref(false);
const { isMobile, state, toggle } = useSidebar({
  open,
  collapsed,
  breakpoint: "(max-width: 767px)",
});
</script>

<template>
  <button type="button" @click="toggle">Toggle sidebar</button>
  <output>{{ state }}</output>

  <Sidebar
    v-model:open="open"
    v-model:collapsed="collapsed"
    :mobile="isMobile"
    collapsible="icon"
  >
    ...
  </Sidebar>
</template>

This mode updates the supplied refs directly. The composable does not emit component events; the connected Sidebar models receive the resulting values.

Options

These options apply to controlled state mode.

OptionTypeDefaultDescription
openRef<boolean>Internal false refMobile dialog visibility.
collapsedRef<boolean>Internal false refDesktop collapse state.
breakpointMaybeRefOrGetter<string>"(max-width: 767px)"Media query used to calculate isMobile.
mobileMaybeRefOrGetter<boolean | undefined>Media query resultOverrides responsive detection. Useful for container layouts, SSR-owned state, and tests.

Return value

PropertyTypeAvailableDescription
openRef<boolean>Both modesWritable mobile visibility. In component ref mode, writes use the component's cancelable change path.
collapsedRef<boolean>Both modesWritable desktop collapse state. In component ref mode, writes use the component's cancelable change path.
isMobileComputedRef<boolean>Both modesCurrent responsive mode.
stateComputedRef<"open" | "closed" | "expanded" | "collapsed">Both modesNormalized responsive state.
sizeComputedRef<number>Component refCurrent expanded width in pixels. Read-only; use v-model:size for arbitrary size changes.
openMobile()() => voidBoth modesOpen mobile dialog state.
closeMobile()() => voidBoth modesClose mobile dialog state.
toggleMobile()() => voidBoth modesToggle mobile dialog state regardless of responsive mode.
expand()() => voidBoth modesExpand desktop state.
collapse()() => voidBoth modesCollapse desktop state. The component ignores this when collapsible is false.
toggleCollapsed()() => voidBoth modesToggle desktop collapse state regardless of responsive mode.
toggle()() => voidBoth modesToggle mobile visibility when mobile; otherwise toggle desktop collapse.
resetSize()() => voidComponent refRestore the component's defaultSize.

When no mobile override is supplied, controlled mode uses matchMedia through VueUse. During SSR it starts in desktop mode and updates after hydration. Supply an SSR-safe mobile value when initial responsive markup must be deterministic.

Component ref mode delegates through Sidebar events. open-change, collapsed-change, and size-change listeners can still cancel changes.

Exported types

TypeDescription
SidebarControllerPublic Sidebar instance contract used with useTemplateRef.
SidebarTargetRead-only ref containing a SidebarController, null, or undefined.
UseSidebarOptionsControlled state mode options.
UseSidebarReturnShared state and actions returned by controlled state mode.
UseSidebarTargetReturnComponent ref return type, including size and resetSize.

API Reference

Models

ModelTypeDefaultDescription
v-model:openbooleandefaultOpenMobile dialog visibility.
v-model:collapsedbooleandefaultCollapsedDesktop collapse state. Ignored when collapsible is false.
v-model:sizenumberdefaultSizeExpanded desktop width in pixels.

Props

PropTypeDefaultDescription
asComponent | string"aside"Desktop panel element.
side"left" | "right""left"Sidebar edge.
collapsiblefalse | "icon" | "offcanvas"falseDesktop collapse behavior.
defaultOpenbooleanfalseInitial uncontrolled mobile visibility.
defaultCollapsedbooleanfalseInitial uncontrolled desktop collapse state.
defaultSizenumber256Initial expanded width in pixels.
minSizenumber192Minimum resized width.
maxSizenumber480Maximum resized width.
collapsedSizenumber48Width in icon collapse mode.
mobileSizenumber288Mobile drawer width.
resizeStepnumber8Keyboard resize amount in pixels. Shift multiplies it by ten.
resizablebooleanfalseRender the accessible resize separator.
transitionbooleantrueEnable desktop width and off-canvas transitions.
mobilebooleanmedia queryForce mobile or desktop rendering.
breakpointstring"(max-width: 767px)"Media query used when mobile is omitted.
closeOnBackdropClickbooleantrueClose the mobile dialog on backdrop interaction.
closeOnNavigatebooleantrueClose mobile mode after activating a same-window link.
swipeToClosebooleantrueEnable directional mobile swipe dismissal.
teleportstring | false"body"Mobile drawer Teleport target.
keyboardShortcutstring | falsefalseCommand/Ctrl shortcut key for responsive toggle.
ariaLabelstring"Sidebar"Desktop landmark and mobile dialog accessible name.
resizeAriaLabelstring"Resize sidebar"Resize separator accessible name.
uiSidebarUiClasses for named structural parts.

Slots

SlotScoped propsDescription
headerSidebarSlotPropsFixed header region.
defaultSidebarSlotPropsScrollable body region.
footerSidebarSlotPropsFixed footer region.
resize-handleSidebarSlotPropsContent inside the generated separator handle.

SidebarSlotProps exposes open, collapsed, isMobile, state, size, openMobile, closeMobile, toggleMobile, expand, collapse, toggleCollapsed, toggle, and resetSize. On mobile, collapsed is always false.

Emits

EventPayloadDescription
open-change[open, details]Cancelable mobile visibility change.
collapsed-change[collapsed, details]Cancelable desktop collapse change.
size-change[size, details]Cancelable pointer, keyboard, or reset size change. Details include previousSize.

Exposed methods

MethodDescription
open / openMobileOpen mobile visibility. open is a concise alias.
close / closeMobileClose mobile visibility. close is a concise alias.
toggleMobileToggle mobile visibility regardless of responsive state.
toggleToggle mobile visibility or desktop collapse based on responsive state.
expand / collapseChange desktop collapse state.
toggleCollapsedToggle desktop collapse state.
resetSizeRestore defaultSize.

Exposed values

ValueTypeDescription
openValuebooleanCurrent mobile visibility.
collapsedValuebooleanCurrent desktop collapse value.
sizeValuenumberCurrent expanded width in pixels.
isMobilebooleanCurrent responsive mode.
stateSidebarStateCurrent open, closed, expanded, or collapsed state.

Prefer useSidebar(sidebarRef) when consuming these values outside the component.

UI Options

KeyDescription
rootResponsive root and desktop width container.
panelDesktop panel or inner mobile panel.
headerFixed header region.
bodyScrollable body region.
footerFixed footer region.
resizeHandleAccessible resize separator.
mobileOverlayMobile modal backdrop.
mobileContentMobile Drawer dialog panel.
mobileWrapperStructural wrapper inside the mobile Drawer.

Styling Hooks

UI keyCSS classData attrs
rootakaza-sidebar-rootdata-akaza-state, data-akaza-side, data-akaza-mobile, data-akaza-collapsible, data-akaza-collapsed, data-akaza-resizing, data-akaza-transition
panelakaza-sidebar-paneldata-akaza-state, data-akaza-side, data-akaza-mobile
headerakaza-sidebar-header
bodyakaza-sidebar-body
footerakaza-sidebar-footer
resizeHandleakaza-sidebar-resize-handledata-akaza-side, data-akaza-resizing
mobileOverlayakaza-sidebar-mobile-overlayDrawer data-akaza-state is also available on the same element.
mobileContentakaza-sidebar-mobile-contentDrawer data-akaza-state and data-akaza-side are also available on the same element.
mobileWrapperakaza-sidebar-mobile-wrapper

Width and motion can also be configured through --akaza-sidebar-size, --akaza-sidebar-collapsed-size, --akaza-sidebar-mobile-size, --akaza-sidebar-transition-duration, and --akaza-sidebar-transition-easing.

Plain class applies to the single root. Use ui for the panel, regions, resize handle, and teleported mobile parts.

Keyboard

KeyBehavior
Arrow Left / Arrow RightResize by resizeStep; direction follows sidebar placement.
Shift + Arrow Left / Shift + Arrow RightResize by ten times resizeStep.
Home / EndResize to minimum or maximum width.
EscapeClose mobile mode and restore focus.
Tab / Shift + TabRemain inside the open mobile dialog.
Command/Ctrl + configured keyToggle current responsive state when keyboardShortcut is enabled.

Pointer, pen, and touch input can resize the desktop separator. Mobile mode supports backdrop and swipe dismissal. Desktop mode remains non-modal and never traps focus.