Component
StableNavigation

Sidebar

The fixed left sidebar is the primary navigation element for all Syhrezz pages. It is role-specific (Admin, Director, Supervisor, Sales), collapsible, and persists its state in localStorage.

Role Variants

Dark — Primary Role
Dark — Director Accent
Light — Clean White
Blue — Sales / Colorful

Anatomy

PartClassDetails
Container.sidebarposition:fixed, height:100vh, width:268px, dark bg, box-shadow right
Collapsed.sidebar.collapsedwidth:68px. Labels fade out via opacity:0 + translateX(-10px)
Logo area.sidebar-logoGradient icon (36-40px) + name + role subtitle. border-bottom.
Nav wrapper.sidebar-navflex:1, overflow-y:auto, hidden scrollbar
Section label.sidebar-section-label10px fw-700-800, UPPERCASE, letter-spacing:1.5px, opacity fades on collapse
Nav item.nav-itemflex, gap:12px, padding:10-12px, radius:10-12px, hover:translateX(4px)
Active item.nav-item.active::before left bar: 3-4px wide, 18-20px tall, accent color, glow
Nav badge.nav-badgemargin-left:auto, 10px fw-800, pill, accent bg
Toggle buttonBottom of sidebar. Saves state to localStorage key: {role}-sidebar-collapsed

Color Variants by Role

VariantSidebar BGActive AccentLogo GradientUse For
Dark#0F172A#3B5BDB#1E293B → #334155Admin, Supervisor
Dark Indigo#0C0F1A#6366F1#6366F1 → #8B5CF6Director / Executive
Light#F8FAFC + border#6366F1#6366F1 → #8B5CF6Manager / Light mode
Bluelinear-gradient(#1e3a8a, #1e40af)#93c5fdrgba(255,255,255,.2)Sales / Colorful brand

AI Implementation Notes

For AI coding assistants: The sidebar is always position:fixed; height:100vh; display:flex; flex-direction:column. The nav uses flex:1; overflow-y:auto with hidden scrollbar. Collapse state is stored in localStorage.getItem('{role}-sidebar-collapsed'). On collapse, labels get opacity:0; transform:translateX(-10px); pointer-events:none. The topbar and main content both have their left offset updated when the sidebar collapses. Active nav item has a ::before left accent bar — NOT a background change on the left edge.

When to Use

The sidebar is used on every application page as the primary navigation. It is not an optional component — every authenticated page must include the sidebar. The only exceptions are auth pages (login, forgot password) and full-page error screens (404, 403).

Properties

PropertyTypeRequiredDefaultDescription
rolestringrequiredDetermines sidebar background, accent color, and logo gradient.
'primary' | 'accent' | 'alternative'
collapsedbooleanoptionalfalseCollapses sidebar to icon-only rail (68px). State persisted in localStorage.
itemsarrayrequiredNavigation items: {label, href, icon, badge, section}. Items with section property render a section label above them.
activePagestringrequiredCurrent page identifier. Matched against item href to set .active class.

Design Decisions

Why persist collapse state in localStorage instead of a cookie or URL param?
Sidebar collapse is a UI preference, not application state. It should persist across page loads and browser sessions without affecting the URL (which would break sharing) or requiring server storage. localStorage is the correct mechanism for client-only UI preferences.

Changelog

v1.0.0July 2026Added
  • 3 role variants (primary, accent, alternative) with distinct backgrounds and accent colors
  • Collapsible to 68px icon rail with localStorage persistence
  • 2-3 level nested submenu support with CSS max-height transition
  • Section labels, nav badges, active indicator bar

States

Dashboard
Active item
bg:rgba(255,255,255,.12), left accent bar
Hover item
Hover
bg:rgba(255,255,255,.07), translateX(3px)
Collapsed (68px)
Icon-only rail, labels hidden

Accessibility

RequirementImplementation
role="navigation"Add to <nav> element. Use aria-label="Main navigation".
KeyboardAll nav items are focusable via Tab. Enter/Space activates. Current page item has aria-current="page".
CollapsedWhen collapsed, labels are visually hidden but icon buttons still need aria-label for screen readers.
Skip linkAdd a visually-hidden skip navigation link before the sidebar: <a href="#main-content" class="skip-link">Skip to content</a>

Composition

Allowed
Every authenticated page must include sidebar
Sidebar + Topbar always appear together
Nested submenus up to 3 levels
Section labels to group nav items
Forbidden
Auth pages (login, forgot password)
Full-page error screens (404, 403)
More than 3 levels of submenu nesting

Best Practices

Do
Group navigation items logically with section labels. Use the same section structure across all roles.
Consistent structure reduces cognitive load when users switch contexts or roles.
Don't
Put all navigation items in a single flat list without sections.
Unsectioned nav becomes hard to scan as the item count grows.

Content Rules

Dashboard
Single noun or concept. Recognizable. Short.
Go to Dashboard Page
Too verbose. Nav labels should be 1-2 words maximum.
MAIN
UPPERCASE, 1 word, broad category
Navigation Items
Too descriptive — section labels are categories, not descriptions

Nested Submenus (2-3 Levels)

Nested navigation allows complex app structures to be organized hierarchically without overwhelming the user. Syhrezz supports up to 3 levels of nesting. Each level uses progressively smaller text, increased indentation, and a distinct visual treatment to maintain clarity.

Visual Hierarchy Rules

LevelClassIndentFontIndicatorIcon
L1 — Parent.sd-item-dark10px13px fw-500Left 3px bar + accent bg18px SVG
L2 — Child.sd-sub-item28px12px fw-5004px dot ::beforeNone
L3 — Grandchild.sd-sub3-item44px11px fw-4003px dot, muted colorNone

Live Demo — 3-Level Nested Sidebar

Dark — Full 3-level navigation
Level anatomy
L1 — Main navigation. Has icon + label + optional chevron + optional badge.
L2 — Sub-items. No icon. Dot marker when active. 28px left padding. Can have chevron for L3.
L3 — Grandchildren. 44px padding. 11px font. Muted color. No further nesting.

Submenu UX Rules

RuleDetail
Max 3 levelsNever nest deeper than L3 (grandchild). If structure requires more depth, reconsider the IA.
max-height animationSubmenus expand/collapse via max-height: 0 → 300px with 0.25s cubic-bezier(0.4,0,0.2,1). Never use display:none toggle — it prevents animation.
Chevron rotationChevron rotates 90deg when open. Transition: transform 0.2s. Indicates direction of expansion.
Parent highlightWhen a child is active, the parent L1 item gets .parent-active class (color:#a5b4fc) even when collapsed. User can always tell which section they're in.
Multiple openMultiple L1 submenus can be open simultaneously. This is intentional — don't auto-close other menus when opening one.
Collapsed sidebarWhen sidebar is collapsed to 68px, all submenus are hidden. Hovering an L1 item shows a flyout tooltip with the label. No nested flyouts on collapsed state.
L2 section labelsOptional section labels within L2 level. Same style as L1 section labels but smaller (8.5px) and indented to 28px.
KeyboardEnter/Space on L1 toggle toggles submenu. Arrow keys navigate within open submenus. Escape collapses current submenu.

Implementation Pattern

/* CSS structure */
.sd-sub-wrap {
  max-height: 0;
  overflow: hidden;
  transition: max-height .25s cubic-bezier(.4,0,.2,1);
}
.sd-sub-wrap.open { max-height: 300px; }

/* JavaScript toggle */
function toggleSub(trigger, menuId) {
  const menu = document.getElementById(menuId);
  const isOpen = menu.classList.contains('open');
  menu.classList.toggle('open', !isOpen);
  trigger.classList.toggle('parent-open', !isOpen);
}

/* HTML structure — 3 levels */
<!-- L1 parent -->
<div class="sd-item-dark" onclick="toggleSub(this,'sub-sales')">
  <svg>...</svg>  Sales
  <svg class="sd-chevron">...</svg>
</div>

<!-- L2 children -->
<div class="sd-sub-wrap" id="sub-sales">
  <div class="sd-sub-item">Prospects</div>

  <!-- L2 parent → L3 children -->
  <div class="sd-sub-item has-children" onclick="toggleSub3(this,'sub3-customers')">
    Customers
    <svg class="sd-chevron">...</svg>
  </div>

  <!-- L3 grandchildren -->
  <div class="sd-sub3-wrap" id="sub3-customers">
    <div class="sd-sub3-item">All Customers</div>
    <div class="sd-sub3-item">Active</div>
  </div>
</div>

Behavior

TriggerBehavior
Toggle collapseWidth transitions 268px ↔ 68px via CSS transition (0.35s cubic-bezier). Labels fade out (opacity:0 + translateX(-10px)). State saved to localStorage. Topbar and main content left offset update simultaneously.
Nav item clickNavigates to href. Active item gets .active class with left accent bar. Previous active item loses class.
Submenu togglemax-height: 0 → 400px transition (0.25s cubic-bezier). Chevron rotates 90deg. Multiple submenus can be open simultaneously.
Mobile opentranslateX(-100%) → translateX(0). Dark overlay appears behind. Tapping overlay closes sidebar.
Nav item hovertranslateX(4px) + bg:rgba(255,255,255,.07) + color:#fff. Transition: 0.2s cubic-bezier.