CngxSidenav
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) plus an auto default, two-way
[(opened)] binding, and content projection via header/footer
slots.
Responsive out of the box: mode defaults to 'auto', which docks the
rail beside the content once the surrounding CngxSidenavLayout is
64rem or wider and overlays it below that. Nothing needs to be bound.
The threshold lives in sidenav-layout.css and nowhere else - a
@container rule writes --cngx-sidenav-layout-wide on the rail and
this component reads the resolved value, so ejecting the skin moves the
breakpoint with it. Any explicit mode pins that mode at every width.
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.
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">
<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>Metadata#
Host#
Providers#
CNGX_HOVER_INTENT_DEFAULTS- useFactory
() => injectSidenavConfig().hover ?? {} CNGX_SIDENAV- useExisting
CngxSidenav
Relationships
Index#
Inputs
HostBindings
HostListeners
Inputs#
Whether hovering the mini rail expands the sidenav to full width.
trueMaximum width constraint during resize. Use a px value: drag and keyboard
clamping (and aria-valuemax) resolve px only; a rem/ch constraint falls
back to the 600px default for clamping and omits the ARIA value.
this.cfg.dimensions?.maxWidth ?? '600px'Width of the collapsed rail in mini mode. Any CSS value.
this.cfg.dimensions?.miniWidth ?? '56px'Minimum width constraint during resize. Use a px value: drag and keyboard
clamping (and aria-valuemin) resolve px only; a rem/ch constraint falls
back to the 120px default for clamping and omits the ARIA value.
this.cfg.dimensions?.minWidth ?? '120px'SidenavModeDrawer mode. 'auto' (the default) resolves to 'side' once the
surrounding layout is 64rem or wider and to 'over' below that; any
other value pins that mode at every width.
'auto'SidenavPositionLogical position: 'start' (default left in LTR) or 'end' (right in LTR).
'start'Accessible name of the resize separator. English default; per-instance
like ariaLabel, since it names this rail's handle.
'Resize navigation'string | undefinedKeyboard 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.
this.cfg.shortcutOutputs#
Instance Properties#
Methods#
Collapse the expanded mini rail back to miniWidth.
Same reconciliation as expand(): transient while expandOnHover=true,
authoritative while expandOnHover=false.
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.
HostBindings#
| Binding | Expression |
|---|---|
[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#
| Event | Handler |
|---|---|
(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 inovermode, withvisibility: hidden)--start- left edge; border-right--end- right edge; border-left, flexorder: 2--resizing- no transitions,user-select: none
On .cngx-nav-group-content:
--open- grid-rows0fr -> 1frexpand 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);--expandedgrows 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-visiblestates; 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-sidenav-resize-handle-focus-outline-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"].darkclass
Pair with
@cngx/themes/material/sidenav-theme- Material 3 rail surface@cngx/themes/material/nav-link-theme- Material 3 nav-link palette