CSS-Only

Sidebar

Fixed sidebar navigation component with collapsible states, icon-only mode, and responsive behavior. Provides visual states only - state management is left to the implementing application.

Example

The sidebar component provides three visual states controlled by the data-state attribute:

Main content area

<aside class="omni-sidebar" data-state="extended">
  <div class="omni-sidebar-header">
    <h2 class="omni-sidebar-title">Navigation</h2>
    <button class="omni-close" aria-label="Close sidebar">
      <svg>...</svg>
    </button>
  </div>
  <div class="omni-sidebar-content">
    <nav class="omni-sidebar-nav">
      <a href="#" class="omni-sidebar-item" data-active="true">
        <span class="omni-sidebar-icon"><svg>...</svg></span>
        <span class="omni-sidebar-text">Dashboard</span>
      </a>
      <a href="#" class="omni-sidebar-item">
        <span class="omni-sidebar-icon"><svg>...</svg></span>
        <span class="omni-sidebar-text">Projects</span>
        <span class="omni-badge" data-variant="primary" data-size="sm">3</span>
      </a>
    </nav>
  </div>
</aside>

States

The sidebar supports three visual states controlled by data-state:

Hidden (default)

The sidebar is completely hidden with width: 0 and translated off-screen. This is the default state when no data-state attribute is present.

<!-- Hidden by default -->
<aside class="omni-sidebar">...</aside>

Icon-Only Mode

Use data-state="icon" for a collapsed sidebar showing only icons. Text labels are hidden.

<aside class="omni-sidebar" data-state="icon">
  <div class="omni-sidebar-content">
    <nav class="omni-sidebar-nav">
      <a href="#" class="omni-sidebar-item" aria-label="Dashboard">
        <span class="omni-sidebar-icon"><svg>...</svg></span>
        <span class="omni-sidebar-text">Dashboard</span>
      </a>
    </nav>
  </div>
</aside>

Extended Mode

Use data-state="extended" for a full-width sidebar with icons and text labels visible.

<aside class="omni-sidebar" data-state="extended">
  <!-- Full navigation with text labels -->
</aside>

Position

Control sidebar position with data-position:

Left (default)

The sidebar is positioned on the left side by default.

<aside class="omni-sidebar" data-state="extended">...</aside>

Right

Use data-position="right" to position the sidebar on the right side.

Main content area

<aside class="omni-sidebar" data-state="extended" data-position="right">
  <!-- Right-positioned sidebar -->
</aside>

Structure

Sidebar Header

Optional header with title and close button. Hidden on desktop by default, shown on mobile (≤900px) for close functionality.

<div class="omni-sidebar-header">
  <h2 class="omni-sidebar-title">Navigation</h2>
  <button class="omni-close" aria-label="Close sidebar">
    <svg>...</svg>
  </button>
</div>

Sidebar Content

Scrollable content area for navigation items. Uses flex-grow to fill available space.

<div class="omni-sidebar-content">
  <nav class="omni-sidebar-nav">
    <!-- Navigation items -->
  </nav>
</div>

Sidebar Items

Navigation items with optional icons, text, and badges. Use data-active="true" to indicate the current page.

<a href="#" class="omni-sidebar-item" data-active="true">
  <span class="omni-sidebar-icon"><svg>...</svg></span>
  <span class="omni-sidebar-text">Dashboard</span>
</a>

<!-- With badge -->
<a href="#" class="omni-sidebar-item">
  <span class="omni-sidebar-icon"><svg>...</svg></span>
  <span class="omni-sidebar-text">Messages</span>
  <span class="omni-badge" data-variant="danger" data-size="sm">5</span>
</a>

<!-- As button -->
<button class="omni-sidebar-item">
  <span class="omni-sidebar-icon"><svg>...</svg></span>
  <span class="omni-sidebar-text">Sign Out</span>
</button>

Responsive Behavior

The sidebar includes basic responsive adjustments:

  • Desktop (>900px): Sidebar header is hidden by default. Use state management to toggle between icon and extended modes.
  • Mobile (≤900px): Sidebar header is shown to provide a close button. Typically shown as overlay with backdrop.
  • State Management: The component provides CSS-only visual states. JavaScript state management, breakpoint decisions, and overlay/backdrop handling are intentionally left to the implementing application.

API Reference

Attribute Values Default Description
data-state hidden, icon, extended hidden Visual state of the sidebar
data-position left, right left Side of the screen for placement
data-active (item) true Marks the current active navigation item

CSS Custom Properties

Property Default Description
--omni-sidebar-width 240px Width of extended sidebar
--omni-sidebar-width-collapsed 64px Width of icon-only sidebar
--omni-navbar-height 64px Height offset for fixed navbar

Classes

Class Element Description
.omni-sidebar <aside> Main sidebar container
.omni-sidebar-header <div> Header with title and close button
.omni-sidebar-title <h2> Sidebar title text
.omni-sidebar-content <div> Scrollable content container
.omni-sidebar-nav <nav> Navigation list container
.omni-sidebar-item <a>, <button> Individual navigation item
.omni-sidebar-icon <span> Icon container
.omni-sidebar-text <span> Text label (hidden in icon mode)

Accessibility

  • Use semantic <nav> element with appropriate aria-label
  • Mark current page with data-active="true" on the corresponding item
  • Icon-only mode requires aria-label on each sidebar item for screen readers
  • Full keyboard navigation support (Tab, Enter, Space for buttons)
  • Focus visible indicators with proper contrast ratios
  • Close button requires aria-label for accessibility
  • Supports prefers-reduced-motion for transitions
  • High contrast mode increases border widths and adds visible borders to active items
  • Works with both <a> links and <button> elements

Best Practices

<!-- ✓ Good: Semantic markup with labels -->
<aside class="omni-sidebar" data-state="icon">
  <div class="omni-sidebar-content">
    <nav class="omni-sidebar-nav" aria-label="Main navigation">
      <a href="/dashboard" class="omni-sidebar-item"
         data-active="true" aria-label="Dashboard">
        <span class="omni-sidebar-icon"><svg>...</svg></span>
        <span class="omni-sidebar-text">Dashboard</span>
      </a>
    </nav>
  </div>
</aside>

<!-- ✗ Bad: Missing aria-label in icon mode -->
<aside class="omni-sidebar" data-state="icon">
  <a href="/dashboard" class="omni-sidebar-item">
    <span class="omni-sidebar-icon"><svg>...</svg></span>
  </a>
</aside>

Components Used

Other OmniUI components demonstrated on this page: