Skip to main content
cngx-src documentation

CngxSidenav

ComponentPrimaryOnPushNo encapsulationv0.1.0WCAG AA

projects/ui/sidenav/sidenav.ts

Import#

import { CngxSidenav } from '@cngx/ui/sidenav'

Description#

Declarative sidebar component for the four drawer modes (over, push, side, mini), with responsive mode switching, two-way [(opened)] binding, and content projection via header/footer slots.

In overlay (over) mode it drives a CDK focus trap directly via FocusTrapFactory (the same primitive CngxFocusTrap wraps): focus moves into the rail on open and is restored to the opener on close. Responsive switching runs off an inline matchMedia listener; the shared backdrop and document scroll lock are coordinated by CngxSidenavLayout. It does not compose CngxDrawer and has no swipe-to-dismiss.

Use inside CngxSidenavLayout for dual-sidebar support and shared backdrop coordination.

<cngx-sidenav-layout>
  <cngx-sidenav position="start" [(opened)]="navOpen"
                [responsive]="'(min-width: 1024px)'">
    <cngx-sidenav-header>Logo</cngx-sidenav-header>
    <a cngxNavLink [active]="true">Dashboard</a>
    <cngx-sidenav-footer>v1.0</cngx-sidenav-footer>
  </cngx-sidenav>
  <cngx-sidenav-content>
    <router-outlet />
  </cngx-sidenav-content>
</cngx-sidenav-layout>

https://cngxjs.github.io/cngx/examples/#/ui/sidenav/dual-sidebar-master-detail https://cngxjs.github.io/cngx/examples/#/ui/sidenav/full-navigation-sidebar https://cngxjs.github.io/cngx/examples/#/ui/sidenav/material-theming-light-vs-dark

Metadata#

Host#

Providers#

CNGX_HOVER_INTENT_DEFAULTS
useFactory () => injectSidenavConfig().hover ?? {}
CNGX_SIDENAV
useExisting CngxSidenav

Relationships

Index#

Inputs#

ariaLabel#string | undefined
input()

Accessible label for the complementary landmark.

expandOnHover#boolean
input()

Whether hovering the mini rail expands the sidenav to full width.

default true
maxWidth#string
input()

Maximum width constraint during resize.

default this.cfg.dimensions?.maxWidth ?? '600px'
miniWidth#string
input()

Width of the collapsed rail in mini mode. Any CSS value.

default this.cfg.dimensions?.miniWidth ?? '56px'
minWidth#string
input()

Minimum width constraint during resize.

default this.cfg.dimensions?.minWidth ?? '120px'
input()

Drawer mode. Overridden by responsive when set.

default 'over'
opened#boolean
model()

Two-way opened state. Supports [(opened)]="signal".

default false
input()

Logical position: 'start' (default left in LTR) or 'end' (right in LTR).

default 'start'
resizable#boolean
input()

Whether the sidebar is user-resizable via a drag handle.

default false
responsive#string | undefined
input()

CSS media query string for responsive mode switching. When the query matches, mode becomes 'side' (permanent). When it doesn't match, mode becomes 'over' (overlay).

default this.cfg.responsive
shortcut#string | undefined
input()

Keyboard shortcut to toggle the sidenav, e.g. 'ctrl+b' or 'meta+b'. Uses ctrl on Windows/Linux and meta (Cmd) on macOS automatically when 'mod+<key>' syntax is used.

default this.cfg.shortcut
width#string
model()

Width of the sidenav panel. Supports two-way [(width)] for resize.

default this.cfg.dimensions?.width ?? '280px'

Outputs#

opened#boolean
model()

Two-way opened state. Supports [(opened)]="signal".

width#string
model()

Width of the sidenav panel. Supports two-way [(width)] for resize.

Instance Properties#

expanded#unknown
Readonly
this.expandedState.asReadonly()
resizing#unknown
Readonly
this.resizingState.asReadonly()

Methods#

close#void

Closes the sidenav (only in over/push mode). No-op in side/mini mode.

collapse#void

Collapse the expanded mini rail back to miniWidth.

Same reconciliation as expand(): transient while expandOnHover=true, authoritative while expandOnHover=false.

expand#void

Expand the mini rail to full width.

When expandOnHover=true (the default) the debounced hover is the source of truth for expanded, so a programmatic expand() is transient: the next pointer edge overrides it. For authoritative programmatic control set expandOnHover=false, which hands expand()/collapse() full authority.

open#void

Opens the sidenav.

toggle#void

Toggles the sidenav.

HostBindings#

BindingExpression
[class.cngx-sidenav]true
[class.cngx-sidenav--start]position() === 'start'
[class.cngx-sidenav--end]position() === 'end'
[class.cngx-sidenav--open]opened()
[class.cngx-sidenav--over]effectiveMode() === 'over'
[class.cngx-sidenav--push]effectiveMode() === 'push'
[class.cngx-sidenav--side]effectiveMode() === 'side'
[class.cngx-sidenav--mini]effectiveMode() === 'mini'
[class.cngx-sidenav--expanded]expanded()
[class.cngx-sidenav--resizable]resizable()
[class.cngx-sidenav--resizing]resizing()
[attr.aria-hidden]effectiveMode() === 'side' || effectiveMode() === 'mini' ? null : !opened()
[attr.aria-modal]overlayActive() ? 'true' : null
[style.--cngx-sidenav-width]effectiveWidth()
[style.--cngx-sidenav-mini-width]miniWidth()
[attr.aria-label]ariaLabel() || null

HostListeners#

EventHandler
(keydown.escape)keydown.escape()

Default structural and thematic styles for CngxSidenav - the rail itself (surface, borders, slots), the four mode variants, mini-mode, the resize handle, and the nav-link rules the rail applies to @cngx/common/interactive nav directives. Shipped via the component's styleUrl, so a bare <cngx-sidenav> is styled without a CngxSidenavLayout wrapper. Under encapsulation: None the cngx-sidenav tag and its descendants match globally; the cngx-sidenav- prefix is the namespace.

CngxSidenavLayout's own styles (flex container, content offset, backdrop scrim, the --ready transition gate, reduced-motion) live in sidenav-layout.css.

State modifiers

On cngx-sidenav:

  • --open - visible (otherwise width collapses to 0 in over mode, with visibility: hidden)
  • --start - left edge; border-right
  • --end - right edge; border-left, flex order: 2
  • --resizing - no transitions, user-select: none

On .cngx-nav-group-content:

  • --open - grid-rows 0fr -> 1fr expand for nav groups

Variants

Mode classes on cngx-sidenav:

  • --push - in flex flow, push content sideways
  • --side - in flex flow, stays visible (no width collapse)
  • --over - absolute-positioned, doesn't push content
  • --mini - icon-rail (--cngx-sidenav-mini-width); --expanded grows to full width with negative margin so the overlay does not shift the flex layout, plus --cngx-sidenav-expanded-shadow

Slots

  • .cngx-sidenav__body - scrollable rail content
  • .cngx-sidenav-header - sticky top slot, border-bottom
  • .cngx-sidenav-footer - sticky bottom slot, border-top, 70% opacity
  • .cngx-sidenav__resize-handle - col-resize drag bar on the rail's edge; tinted on hover / drag via --cngx-sidenav-resize-handle-color
  • .cngx-nav-link - nav-link rule with hover / --active / :focus-visible states; mini mode hides labels and renders first-letter initials via [data-initial]::before
  • .cngx-nav-group-content - grid-rows expand/collapse wrapper for nested nav groups

Mini-mode also hides [cngxNavLabel], [cngxNavGroup], and [cngxNavBadge].

Nav-class contract

The rail styles a set of class / attribute hooks emitted by the @cngx/common/interactive nav directives. These form a cross-lib contract: rename any hook in @cngx/common and mini-mode plus active-state styling break silently. sidenav-nav-contract.spec.ts mounts the real directives inside a cngx-sidenav and asserts the hooks still resolve, so a rename fails a test instead. The hooks:

  • .cngx-nav-link / .cngx-nav-link--active (CngxNavLink)
  • [data-initial] - first-letter initial shown in mini mode (CngxNavLink)
  • [cngxNavLabel] (CngxNavLabel), [cngxNavGroup] (CngxNavGroup), [cngxNavBadge] (CngxNavBadge), all hidden in collapsed mini mode
  • .cngx-nav-group-content / --open, the nested nav-group expand / collapse wrapper

Inheritance

  • --cngx-sidenav-bg -> --cngx-color-surface
  • --cngx-sidenav-border-color -> --cngx-color-border
  • --cngx-sidenav-footer-border-color -> --cngx-sidenav-border- color -> --cngx-color-border
  • --cngx-sidenav-resize-handle-color -> --cngx-color-primary
  • --cngx-nav-link-focus-outline-color -> --cngx-color-primary

Dark mode

Three hooks deepen the expanded-rail shadow and flip the nav-link hover / active overlays from alpha-on-black to alpha-on-white:

  • prefers-color-scheme: dark
  • [data-color-scheme="dark"]
  • .dark class

Pair with

  • @cngx/themes/material/sidenav-theme - Material 3 rail surface
  • @cngx/themes/material/nav-link-theme - Material 3 nav-link palette

Index#

Layout

--cngx-sidenav-width#<length>
Default value 280px

Default open-width of the rail.

--cngx-sidenav-padding#<length>
Default value 16px

Padding shorthand inside the header / footer slots.

--cngx-sidenav-resize-handle-width#<length>
Default value 4px

Width of the drag-to-resize handle on the rail's edge.

Surface

--cngx-sidenav-bg#<color>
Default value oklch(0.97 0.005 250)

Background of the rail surface.

--cngx-sidenav-color#*
Default value currentColor

Text color of the rail. Defaults to currentColor so it inherits from the page.

--cngx-sidenav-border-width#<length>
Default value 1px

Stroke width of the rail edge border.

--cngx-sidenav-border-color#<color>
Default value oklch(0.89 0 0)

Stroke color of the rail edge border. Falls back through --cngx-color-border.

--cngx-sidenav-header-bg#<color>
Default value transparent

Background of the header slot.

Motion

--cngx-sidenav-transition-duration#<time>
Default value 0.25s

Duration of the open / close / mini transitions.

--cngx-sidenav-transition-easing#*
Default value ease

Easing curve of the open / close / mini transitions.

Variant / Mini

--cngx-sidenav-mini-width#<length>
Default value 56px

Collapsed width in mini mode (icon-rail).

--cngx-sidenav-expanded-shadow#*
Default value 4px 0 12px oklch(0 0 0 / 0.1)

Drop-shadow applied when the mini-rail expands over content.

Typography

--cngx-sidenav-header-font-size#*
Default value 0.875rem

Font-size of the header slot.

State / Resize

--cngx-sidenav-resize-handle-color#<color>
Default value oklch(0.66 0.19 50)

Color of the resize handle on hover / drag. Falls back to --cngx-color-primary.

See: [[--cngx-color-primary]]

State / Over

--cngx-sidenav-backdrop-bg#<color>
Default value oklch(0 0 0)

Background of the mobile backdrop scrim.

--cngx-sidenav-backdrop-opacity#<number>
Default value 0.5

Opacity of the mobile backdrop scrim.

State / Hover

State / Active

State / Focus