Sidebar is the collapsible-rail flagship of the styled layer: a flat ItemsControl of
NaviusSidebarSection and/or bare NaviusSidebarItem children (the same manual-composition
anatomy NaviusBreadcrumb uses), plus optional header/footer content slots and a built-in collapse
toggle. IsCollapsed is registered via DependencyProperty.RegisterAttached (with
GetIsCollapsed/SetIsCollapsed accessors) carrying FrameworkPropertyMetadataOptions.Inherits,
so every descendant (section headers, item labels, the collapse toggle) reacts to it through a
plain template trigger with no manual state push-down. The attached registration is what makes the
inheritance real: Register-applied Inherits metadata never leaves the owner type, so other
element types would read the false default forever. Roving keyboard focus
(ArrowUp/ArrowDown/Home/End) walks the realized visual tree for NaviusSidebarItem
instances in visual order, flattening across section boundaries deliberately: the contract is one
continuous nav list, and sections are only visual
grouping. The index math lives in the SidebarNavigation.MoveFocus/ToggleCollapsed helpers, free
of any UI-thread/Application dependency (though MoveFocus still takes a
System.Windows.Input.Key, so it is UI-thread/Application-free but not WPF-assembly-free), unit
tested directly.
Expanded (IsCollapsed = false, the default): the root is ExpandedWidth (240px by
default). Each NaviusSidebarItem shows its icon plus label, section headers are visible, and
the footer toggle button reads “Collapse” with a left-pointing chevron.
Collapsed (IsCollapsed = true): the root animates (or snaps, see below) to CollapsedWidth
(64px by default). Item labels and section headers collapse to Visibility.Collapsed via
DataTriggers bound to the inherited NaviusSidebar.IsCollapsed value, each item’s icon
re-centers, and the footer toggle’s label hides while its chevron flips to point right.
The transition between the two is a 150ms CubicEase-out DoubleAnimation on the root part’s
Width, started from OnIsCollapsedChanged. When ReducedMotion.AnimationsEnabled is false, or
there is no live PresentationSource (design time / not yet shown), the width is set instantly
instead of animated. The instant-set path was a confirmed M6 audit fix: AnimateWidth originally
ran the animation unconditionally with no reduced-motion guard, unlike the sibling looping
animations in Skeleton/Spinner; it now short-circuits through the same ReducedMotion.AnimationsEnabled
seam via a using Navius.Wpf.Ui.Internal; import.
Two-way bindable by default. Registered via RegisterAttached with Inherits (plus GetIsCollapsed/SetIsCollapsed accessors), so descendants of any element type read the same value through property value inheritance without a manual push-down — Register-applied Inherits never propagates beyond the owner type.
ExpandedWidth
double
240
NaviusSidebar
Root width while expanded.
CollapsedWidth
double
64
NaviusSidebar
Root width while collapsed.
HeaderContent
object?
null
NaviusSidebar
Content above the item list (e.g. a logo/brand lockup).
FooterContent
object?
null
NaviusSidebar
Content below the item list, above the built-in collapse toggle (e.g. a user/account row).
Icon
object?
null
NaviusSidebarItem
Icon content, shown at a fixed width whether the sidebar is collapsed or expanded.
IsActive
bool
false
NaviusSidebarItem
True for the current page/section; renders the Accent wash and a left-edge indicator bar. Setting it applies (or clears) AutomationProperties.ItemStatus.
Header
object?
null
HeaderedItemsControl (via NaviusSidebarSection)
The section label; hidden via template trigger while IsCollapsed.
NaviusSidebar ships NaviusSidebarAutomationPeer (a FrameworkElementAutomationPeer reporting
AutomationControlType.Group, class name NaviusSidebar) rather than relying on the default
ItemsControl peer: ItemsControlAutomationPeer’s children are only item peers for the Items
collection, which dropped FooterContent descendants and the built-in collapse button from the
UIA tree entirely (navius-wpf issue #28). Deriving FrameworkElementAutomationPeer restores the
default visual-tree child walk, so footer descendants and the collapse button now appear in the
Control view; Group is the closest fit because UIA has no navigation-landmark control type. The
collapse button is a regular Button — its peer exposes InvokePattern natively — and carries a
state-aware accessible name (“Collapse sidebar” / “Expand sidebar”) via a style DataTrigger on
the inherited IsCollapsed value, since its visible “Collapse” label hides while collapsed and
would otherwise leave it nameless. Covered by
NaviusSidebar_AutomationPeer_ExposesFooterAndCollapseDescendants,
NaviusSidebar_CollapseButton_AccessibleNameReflectsState, and
NaviusSidebar_IsCollapsed_InheritsToDescendantsAndCollapsesItemLabels in UiSidebarTests.cs.
NaviusSidebarItem derives ButtonBase directly rather than the concrete Button type, and now
ships its own NaviusSidebarItemAutomationPeer (a FrameworkElementAutomationPeer implementing
IInvokeProvider), the same shape as NaviusBreadcrumbItem’s peer: it reports
AutomationControlType.Button, throws ElementNotEnabledException from Invoke when disabled,
and otherwise queues activation onto the item’s dispatcher (DispatcherPriority.Input) per the
UIA Invoke contract’s requirement to return immediately, running it through ButtonBase.OnClick
rather than a bare Click raise so a bound Command executes. Another automation touch is
imperative: OnIsActiveChanged calls AutomationProperties.SetItemStatus(d, "current") when
IsActive becomes true and clears it otherwise, verified by
NaviusSidebarItem_IsActive_SetsItemStatusAutomationProperty. The unit suite
(UiSidebarTests.cs) also exercises the item peer’s Button control type, the Invoke pattern’s
presence, the disabled-throws behavior, and that an enabled Invoke raises Click and executes a
bound Command exactly once the dispatcher queue is pumped; it otherwise covers
SidebarNavigation.MoveFocus/ToggleCollapsed as pure functions and the NaviusSidebar defaults
(IsCollapsed, ExpandedWidth, CollapsedWidth) and ToggleCollapsedCommand round trip.