Skip to content

Sidebar

A structured navigation sidebar with three distinct sections: a header for branding, a scrollable content area for navigation, and a footer for secondary actions. Use the dedicated sidebar components (CoarSidebarItem, CoarSidebarGroup, CoarSidebarHeading, CoarSidebarDivider, CoarSidebarSpacer) for full collapsed/expanded support with automatic tooltips.

ts
import {
  CoarSidebar,
  CoarSidebarItem,
  CoarSidebarGroup,
  CoarSidebarHeading,
  CoarSidebarDivider,
  CoarSidebarSpacer,
} from '@cocoar/vue-ui';

Use CoarSidebarItem for navigation, CoarSidebarGroup for expandable or flyout sections, and CoarSidebarHeading for section labels. Items go directly into the sidebar — no CoarMenu wrapper needed.

Toggle collapsed for icon-only mode with automatic tooltips. Groups support two modes: expand (inline panel with plus/minus indicator) and flyout (floating panel with chevron indicator). Use the controls to explore all options.

Main content area
vue
<template>
  <div style="display: flex; flex-direction: column; gap: 16px;">
    <div style="display: flex; flex-wrap: wrap; gap: 12px; align-items: center;">
      <CoarCheckbox v-model="collapsed" label="collapsed" />
      <CoarSelect v-model="size" :options="sizeOptions" label="size" size="s" style="width: 100px;" />
      <CoarSelect v-model="variant" :options="variantOptions" label="variant" size="s" style="width: 140px;" />
      <CoarCheckbox v-model="elevated" label="elevated" />
      <CoarCheckbox v-model="borderless" label="borderless" />
    </div>

    <div style="height: 560px; border: 1px solid var(--coar-border-neutral-secondary); border-radius: 8px; overflow: hidden; display: flex;">
      <CoarSidebar
        v-model:collapsed="collapsed"
        :size="size"
        :variant="variant"
        :elevated="elevated"
        :borderless="borderless"
      >
        <template #header="{ collapsed: isCollapsed }">
          <div style="display: flex; align-items: center; gap: 8px; padding: 4px;">
            <div style="width: 28px; height: 28px; background: var(--coar-background-accent-primary); color: white; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 14px; flex-shrink: 0;">C</div>
            <strong v-if="!isCollapsed" style="white-space: nowrap;">cocoar</strong>
          </div>
        </template>

        <CoarSidebarItem icon="home" label="Dashboard" active />
        <CoarSidebarItem icon="user" label="Profile" />
        <CoarSidebarItem icon="list" label="Projects" />
        <CoarSidebarItem label="No Icon Item" />

        <CoarSidebarHeading label="Management" />
        <CoarSidebarGroup icon="users" label="Users" v-model:open="usersOpen">
          <CoarSidebarItem icon="user-plus" label="All Users" />
          <CoarSidebarItem icon="shield" label="Roles" />
          <CoarSidebarItem icon="lock" label="Permissions" />
        </CoarSidebarGroup>
        <CoarSidebarGroup icon="list" label="Reports (hover)" mode="flyout" open-on-hover>
          <CoarSidebarItem icon="globe" label="Sales" />
          <CoarSidebarItem icon="bell" label="Alerts" />
          <CoarSidebarGroup icon="settings" label="Nested flyout" mode="flyout">
            <CoarSidebarItem icon="lock" label="Audit Log" />
            <CoarSidebarItem icon="shield" label="Compliance" />
          </CoarSidebarGroup>
          <CoarSidebarGroup icon="list" label="Nested expand" v-model:open="expandInFlyout">
            <CoarSidebarItem icon="user-plus" label="Create" />
            <CoarSidebarItem icon="settings" label="Configure" />
          </CoarSidebarGroup>
        </CoarSidebarGroup>
        <CoarSidebarGroup icon="settings" label="Quick Actions (icons)" mode="flyout" icon-only>
          <CoarSidebarItem icon="user-plus" label="Add User" />
          <CoarSidebarItem icon="lock" label="Lock" />
          <CoarSidebarGroup icon="bell" label="Nested icons" mode="flyout">
            <CoarSidebarItem icon="bell" label="Notify" />
            <CoarSidebarItem icon="shield" label="Security" />
          </CoarSidebarGroup>
          <CoarSidebarGroup icon="list" label="Expand" v-model:open="expandInIconOnly">
            <CoarSidebarItem icon="user-plus" label="Create" />
            <CoarSidebarItem icon="settings" label="Configure" />
          </CoarSidebarGroup>
        </CoarSidebarGroup>

        <CoarSidebarHeading label="System" />
        <CoarSidebarItem icon="settings" label="Settings" />
        <CoarSidebarItem icon="globe" label="Localization" />

        <template #footer>
          <CoarSidebarDivider />
          <CoarSidebarItem icon="log-out" label="Logout" />
          <CoarSidebarSpacer height="4px" />
        </template>
      </CoarSidebar>

      <div style="flex: 1; padding: 24px; display: flex; align-items: center; justify-content: center; color: var(--coar-text-neutral-tertiary);">
        Main content area
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import {
  CoarSidebar,
  CoarSidebarItem,
  CoarSidebarGroup,
  CoarSidebarHeading,
  CoarSidebarDivider,
  CoarSidebarSpacer,
  CoarCheckbox,
  CoarSelect,
} from '@cocoar/vue-ui';
import type { CoarSelectOption } from '@cocoar/vue-ui';

const collapsed = ref(false);
const size = ref<'s' | 'm' | 'l'>('m');
const variant = ref<'primary' | 'secondary'>('primary');
const elevated = ref(false);
const borderless = ref(false);
const usersOpen = ref(false);
const reportsOpen = ref(false);
const expandInFlyout = ref(false);
const expandInIconOnly = ref(false);

const sizeOptions: CoarSelectOption<string>[] = [
  { value: 's', label: 's (16px)' },
  { value: 'm', label: 'm (20px)' },
  { value: 'l', label: 'l (24px)' },
];

const variantOptions: CoarSelectOption<string>[] = [
  { value: 'primary', label: 'primary' },
  { value: 'secondary', label: 'secondary' },
];
</script>

Side / Orientation

The side prop attaches the sidebar to any of the four edges. left and right give a vertical column (the classic navigation rail); top and bottom switch the layout to a horizontal toolbar. Tooltip placement, flyout direction, the active-state indicator border, and the collapsed dimension (width vs. height) all adapt automatically.

Use the side selector below to flip between all four orientations on the same content.

Note: in horizontal sidebars `mode="expand"` opens to the right; `mode="flyout"` opens downward (top) or upward (bottom).
Main content area
Last clicked:
vue
<template>
  <div style="display: flex; flex-direction: column; gap: 16px;">
    <div style="display: flex; flex-wrap: wrap; gap: 12px; align-items: center;">
      <CoarSelect
        v-model="side"
        :options="sideOptions"
        label="side"
        size="s"
        style="width: 140px;"
      />
      <CoarCheckbox v-model="collapsed" label="collapsed" />
      <CoarCheckbox v-model="elevated" label="elevated" />
      <CoarCheckbox v-model="borderless" label="borderless" />
      <span style="color: var(--coar-text-neutral-tertiary); font-size: 13px;">
        Note: in horizontal sidebars `mode="expand"` opens to the right; `mode="flyout"` opens downward (top) or upward (bottom).
      </span>
    </div>

    <div
      :style="containerStyle"
      style="height: 480px; border: 1px solid var(--coar-border-neutral-secondary); border-radius: 8px; overflow: hidden;"
    >
      <CoarSidebar
        v-model:collapsed="collapsed"
        :side="side"
        :elevated="elevated"
        :borderless="borderless"
      >
        <CoarSidebarItem icon="home" label="Home" active @click="lastClicked = 'Home'" />
        <CoarSidebarItem icon="user" label="Profile" @click="lastClicked = 'Profile'" />
        <CoarSidebarItem icon="list" label="Projects" @click="lastClicked = 'Projects'" />

        <CoarSidebarGroup icon="users" label="Team" v-model:open="teamOpen">
          <CoarSidebarItem icon="user-plus" label="Members" @click="lastClicked = 'Members'" />
          <CoarSidebarItem icon="shield" label="Roles" @click="lastClicked = 'Roles'" />
        </CoarSidebarGroup>

        <CoarSidebarGroup icon="settings" label="Tools" mode="flyout">
          <CoarSidebarItem icon="bell" label="Notifications" @click="lastClicked = 'Notifications'" />
          <CoarSidebarItem icon="lock" label="Security" @click="lastClicked = 'Security'" />
          <CoarSidebarItem icon="globe" label="Localization" @click="lastClicked = 'Localization'" />
        </CoarSidebarGroup>

        <CoarSidebarItem icon="settings" label="Settings" @click="lastClicked = 'Settings'" />
      </CoarSidebar>

      <div
        style="flex: 1; padding: 24px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; color: var(--coar-text-neutral-tertiary); text-align: center;"
      >
        <div>Main content area</div>
        <div style="font-size: 13px;">Last clicked: <strong>{{ lastClicked }}</strong></div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue';
import {
  CoarSidebar,
  CoarSidebarItem,
  CoarSidebarGroup,
  CoarCheckbox,
  CoarSelect,
} from '@cocoar/vue-ui';
import type { CoarSelectOption } from '@cocoar/vue-ui';

type Side = 'left' | 'right' | 'top' | 'bottom';

const side = ref<Side>('left');
const collapsed = ref(false);
const elevated = ref(false);
const borderless = ref(false);
const teamOpen = ref(false);
const lastClicked = ref('—');

const sideOptions: CoarSelectOption<Side>[] = [
  { value: 'left', label: 'left' },
  { value: 'right', label: 'right' },
  { value: 'top', label: 'top' },
  { value: 'bottom', label: 'bottom' },
];

// Container layout flips based on side:
// - left/right: flex-row, sidebar at start or end
// - top/bottom: flex-column, sidebar at start or end
const containerStyle = computed(() => {
  switch (side.value) {
    case 'right':
      return { display: 'flex', flexDirection: 'row-reverse' as const };
    case 'top':
      return { display: 'flex', flexDirection: 'column' as const };
    case 'bottom':
      return { display: 'flex', flexDirection: 'column-reverse' as const };
    default:
      return { display: 'flex', flexDirection: 'row' as const };
  }
});
</script>

Migrating from Menu-based Sidebar

If you are using CoarMenu and CoarMenuItem inside CoarSidebar, we recommend migrating to the new sidebar-specific components. The new components support collapsed mode with automatic tooltips, flyout panels, icon-only mode, and nested groups — none of which work with the menu-based approach.

Before (menu-based):

vue
<CoarSidebar v-model:collapsed="collapsed">
  <CoarMenu>
    <CoarMenuItem icon="home" label="Dashboard" />
    <CoarMenuItem icon="user" label="Profile" />
    <CoarSubExpand icon="users" label="Users">
      <CoarMenuItem icon="user-plus" label="All Users" />
      <CoarMenuItem icon="shield" label="Roles" />
    </CoarSubExpand>
  </CoarMenu>
</CoarSidebar>

After (sidebar components):

vue
<CoarSidebar v-model:collapsed="collapsed">
  <CoarSidebarItem icon="home" label="Dashboard" active />
  <CoarSidebarItem icon="user" label="Profile" />
  <CoarSidebarGroup icon="users" label="Users" v-model:open="usersOpen">
    <CoarSidebarItem icon="user-plus" label="All Users" />
    <CoarSidebarItem icon="shield" label="Roles" />
  </CoarSidebarGroup>
</CoarSidebar>

Key differences:

  • No CoarMenu wrapper — items go directly into the sidebar
  • CoarSidebarItem replaces CoarMenuItem (same props: icon, label, active, disabled)
  • CoarSidebarGroup replaces CoarSubExpand — add mode="flyout" for flyout behavior
  • Headings use CoarSidebarHeading instead of custom markup
  • Footer items use <template #footer> slot — they stretch to full width automatically

API

CoarSidebar

Props

PropTypeDefaultDescription
side'left' | 'right' | 'top' | 'bottom''left'Which edge the sidebar attaches to. top/bottom switch the layout to horizontal (items in a row, scrolls horizontally). Flyout submenus and tooltip placements adapt automatically.
position'left' | 'right'Deprecated. Use side instead. Still accepted as an alias for backwards compatibility.
collapsedbooleanfalseNarrow/icon-only collapsed state. Supports v-model:collapsed. In horizontal sidebars this collapses height instead of width.
size's' | 'm' | 'l''m'Icon size: s (16px), m (20px), l (24px)
variant'primary' | 'secondary''primary'Background color variant
elevatedbooleanfalseShow elevation shadow
borderlessbooleanfalseHide the border
ariaLabelstring'Sidebar'Accessible label for the nav landmark

Slots

All slots receive { collapsed: boolean } as scoped slot props.

SlotDescription
#headerStart of the main axis — top in vertical sidebars, left in horizontal. Use for logo, brand, workspace switcher
defaultScrollable content area — sidebar items. Scrolls vertically in vertical sidebars, horizontally in horizontal ones
#footerEnd of the main axis — bottom in vertical sidebars, right in horizontal. Use for user profile, logout, secondary actions

CoarSidebarItem

PropTypeDefaultDescription
labelstring(required)Item label text
iconstringIcon name (recommended for collapsed mode)
activebooleanfalseHighlight as current page
disabledbooleanfalseDisabled state

Events: @click — standard MouseEvent

CoarSidebarGroup

PropTypeDefaultDescription
labelstring(required)Group label text
iconstringIcon name (recommended for collapsed mode)
disabledbooleanfalseDisabled state
mode'expand' | 'flyout''expand'expand: inline animated panel (plus/minus icon). flyout: floating panel next to the sidebar (chevron icon).
openbooleanfalseExpanded state (expand mode). Supports v-model:open.
icon-onlybooleanfalseFlyout shows icon-only items with tooltips (no labels). Inherited by nested groups. Use :icon-only="collapsed" for dynamic behavior.
open-on-hoverbooleanfalseOpen flyout on hover (200ms delay) instead of click. Only applies to mode="flyout".

CoarSidebarHeading

PropTypeDefaultDescription
labelstring(required)Section heading text. Hidden when sidebar is collapsed (small spacer remains).

CoarSidebarDivider

No props. Renders a horizontal separator line.

CoarSidebarSpacer

PropTypeDefaultDescription
heightstringvar(--coar-spacing-m)CSS height value (e.g. '8px', '1rem')
growbooleanfalseIf true, fills available space (flex: 1)

CSS Tokens

TokenDefaultDescription
--coar-sidebar-width16remDefault width (vertical sidebars)
--coar-sidebar-collapsed-widthsize-aware — s: 2.25rem, m: 2.75rem, l: 3.25remWidth in collapsed mode. Auto-scales with size; set this token to override.
--coar-sidebar-heightautoDefault height (horizontal sidebars)
--coar-sidebar-collapsed-heightsize-aware — same scale as collapsed-widthHeight in collapsed mode. Auto-scales with size; set this token to override.
--coar-sidebar-item-padding0.5rem 0.75remItem padding
--coar-sidebar-item-gap0.75remGap between icon and label
--coar-sidebar-item-margin-horizontal0 2pxItem margin in horizontal sidebars
--coar-sidebar-item-hoverneutral tertiaryHover background
--coar-sidebar-item-active-coloraccent primaryActive text color
--coar-sidebar-item-active-bgaccent tertiaryActive background
--coar-sidebar-group-indent16pxChild indent for mode="expand" (vertical only)

Released under the Apache-2.0 License.