SidebarSecondary
The secondary navigation panel, with collapsible sections and a resizable width.
Usage
import {
SidebarSecondary,
SidebarSecondaryHeader,
SidebarSecondaryContent,
SidebarSecondaryFooter,
SidebarSecondarySection,
SidebarSecondarySectionLabel,
SidebarSecondaryMenu,
SidebarSecondaryMenuItem,
SidebarSecondaryMenuItemExtras,
SidebarSecondaryCollapseTrigger,
} from '@acronis-platform/ui-react';SidebarSecondary is the second-level navigation panel that sits beside
SidebarPrimary. It supports expandable
SidebarSecondarySections for grouping items. The panel itself owns a
controlled/uncontrolled expanded width state and — unless you opt out with
resizable={false} — a draggable resize edge on its inline-end border (see
Resizing). The root renders a <nav> labelled
"Section navigation" by default. SidebarSecondary and the menu-item parts
are polymorphic via the render prop. Themed by the
--ui-sidebar-secondary-* tokens.
The collapsed rail's vertical breadcrumb is rendered by the root
automatically — it derives the parent label from SidebarSecondaryHeader
and the current-page label from the selected SidebarSecondaryMenuItem, so
there is nothing to wire up and no part to place.
Row labels truncate rather than wrap, and a label that is actually clipped gets a tooltip on hover (anchored to the row, opening to the inline-end side). In the collapsed rail every icon-only row shows its label as a tooltip so it stays identifiable.
Examples
A panel with two sections and a footer collapse trigger:
<SidebarSecondary>
<SidebarSecondaryHeader label="Protection" />
<SidebarSecondaryContent>
<SidebarSecondarySection>
<SidebarSecondarySectionLabel>Overview</SidebarSecondarySectionLabel>
<SidebarSecondaryMenu>
<SidebarSecondaryMenuItem href="#" icon={<LayoutGridIcon />} selected>
Dashboard
</SidebarSecondaryMenuItem>
<SidebarSecondaryMenuItem href="#" icon={<ServerIcon />}>
Workloads
</SidebarSecondaryMenuItem>
</SidebarSecondaryMenu>
</SidebarSecondarySection>
<SidebarSecondarySection>
<SidebarSecondarySectionLabel>Resources</SidebarSecondarySectionLabel>
<SidebarSecondaryMenu>
<SidebarSecondaryMenuItem href="#" icon={<BoxIcon />} selected>
Backups
</SidebarSecondaryMenuItem>
<SidebarSecondaryMenuItem href="#">Archived</SidebarSecondaryMenuItem>
</SidebarSecondaryMenu>
</SidebarSecondarySection>
</SidebarSecondaryContent>
<SidebarSecondaryFooter>
<SidebarSecondaryMenu>
<SidebarSecondaryCollapseTrigger icon={<ChevronLeftIcon />}>
Collapse
</SidebarSecondaryCollapseTrigger>
</SidebarSecondaryMenu>
</SidebarSecondaryFooter>
</SidebarSecondary>An expandable section — the in-panel disclosure level, on top of the panel's own expanded/collapsed width:
<SidebarSecondarySection expandable defaultOpen>
<SidebarSecondarySectionLabel>Settings</SidebarSecondarySectionLabel>
<SidebarSecondaryMenu>
<SidebarSecondaryMenuItem href="#">General</SidebarSecondaryMenuItem>
</SidebarSecondaryMenu>
</SidebarSecondarySection>Controlled collapse:
function ProtectionNav() {
const [expanded, setExpanded] = React.useState(true);
return (
<SidebarSecondary expanded={expanded} onExpandedChange={setExpanded}>
{/* … */}
</SidebarSecondary>
);
}Resizing
resizable defaults to true, so the panel ships with a role="separator"
edge on its inline-end border. Width is independent of the expanded/collapsed
state and persists across collapse/expand cycles. The resting width stays
token-driven (--ui-sidebar-secondary-expanded-container-width) until the user
actually resizes or you pass a controlled width, so brand overrides of the
token are honored out of the box. The drag range itself is fixed at the
token's shipped default (256px) and twice that — it does not track a brand
override of the token's value.
| Interaction | Result |
|---|---|
| Drag the edge | Resizes between 256px (the token's default) and 512px |
| Drag past half the min width | Collapses the panel to the rail |
| Click the edge | Toggles expanded/collapsed |
| Double-click the edge | Resets to the default width |
| ← / → | Shrinks/grows by 16px; past the minimum collapses the rail |
| Enter / Space | Toggles expanded/collapsed |
| Home | Expands (if collapsed) and resets to the default width |
Arrow keys follow the writing direction — under dir="rtl" ← grows
and → shrinks. The rows above assume the default
collapsible={true}; see
Locking the collapse state for how each one
behaves when collapsing is disabled.
The edge is labelled 'Resize sidebar' and its hover tooltip explains the
drag/click/double-click gestures. All of that copy is English by default and
must be localized by the consumer — or suppressed with null:
<SidebarSecondary
resizeAriaLabel="Redimensionar la barra lateral"
resizeTooltipExpanded={
<>
<span className="font-semibold">Redimensionar:</span> Arrastrar
</>
}
resizeTooltipCollapsed={null} // no tooltip while collapsed
>
{/* … */}
</SidebarSecondary>To opt out of resizing entirely, pass resizable={false} — the edge is not
rendered and the width follows the tokens alone.
Locking the collapse state
collapsible defaults to true. Pass collapsible={false} to stop the
user changing the panel's expanded/collapsed state:
<SidebarSecondary collapsible={false}>{/* … */}</SidebarSecondary>Every interaction in the Resizing table that would collapse or
expand the panel becomes inert, and the footer
SidebarSecondaryCollapseTrigger renders natively disabled (with no
aria-expanded, since it has no state to flip):
| Interaction | With collapsible={false} |
|---|---|
| Drag past half the min width (while expanded) | Clamps to 256px instead of collapsing |
| Drag the edge (while collapsed) | Nothing |
| Click the edge | Nothing |
| Double-click the edge | Still resets the width; never expands |
| ← (shrink, while expanded) | Clamps to 256px instead of collapsing |
| ← (shrink, while collapsed) | Nothing |
| → (grow, while collapsed) | Nothing |
| Enter / Space | Nothing |
| Home | Resets to the default width; does not expand |
| Footer collapse trigger | disabled, and shows no Expand tooltip |
While the panel is expanded, resizing itself stays fully live — only the
collapse transition is suppressed. Combine with resizable={false} to lock the
width outright.
collapsible does not force expanded to a value: collapsible={false} with
defaultExpanded={false} renders a permanently collapsed rail, and a controlled
expanded prop keeps full authority either way.
In that permanently-collapsed state the resize edge remains a focusable tab stop with its accessible name, but it is mostly inert: dragging it, clicking it and both Arrow keys do nothing observable, and Enter / Space are fully inert.
Two gestures survive — Home and a double-click on the edge. Both
reset the stored width to defaultWidth; neither is gated on collapsible (in
the double-click handler, only the expand is). They fire onWidthChange only
when defaultWidth differs from the current stored width — a width write that
resolves to the current value is a no-op, so on a panel whose width has never
moved these two gestures write nothing at all. When the width has moved, nothing
moves back on screen at that moment — the rail stays collapsed — but a
controlled consumer sees the new width, and it applies as soon as the panel is
expanded via the expanded prop.
With collapsible={false} every tooltip on the panel is adjusted for you, so
the copy never advertises a gesture that does nothing:
- The footer collapse trigger — its
expandTooltipis suppressed outright. The button isdisabled, so an "Expand" hint would promise an action the user can't take. This one is not overridable: passingexpandTooltipexplicitly does not bring the tooltip back.
The two resize-edge tooltip defaults narrow instead:
- Expanded — the default drops the "Collapse: Click" line and reads "Resize: Drag" / "Reset size: Double click". Both of those still work.
- Collapsed — the default narrows to "Reset size: Double click" alone. Dragging the edge only ever tries to expand (gated off) and clicking bails, so the double-click is the one pointer gesture still worth describing.
An explicit resizeTooltipExpanded / resizeTooltipCollapsed value always wins
over the default, collapsible notwithstanding — pass null to suppress a
tooltip, or a node to replace the default copy.
API Reference
SidebarSecondary
SidebarSecondaryHeader
SidebarSecondarySection
SidebarSecondarySectionLabel
actions renders trailing header controls (e.g. a ghost ButtonIcon) as a
sibling of the expandable section's toggle, never nested inside it — so
activating an action doesn't toggle the section. unreadRollup is a summary
badge that only shows while an expandable section is closed; it is ignored on
static sections.
<SidebarSecondarySectionLabel
actions={
<ButtonIcon variant="ghost" aria-label="Add policy">
<PlusIcon />
</ButtonIcon>
}
unreadRollup={<Tag variant="info">3</Tag>}
>
Policies
</SidebarSecondarySectionLabel>SidebarSecondaryMenuItem
SidebarSecondaryMenuItemExtras
SidebarSecondaryCollapseTrigger
A single icon covers both directions — it rotates 180° between the expanded
and collapsed states. While collapsed the button's label is sr-only and
expandTooltip (default 'Expand', so localize it) is shown on hover instead —
unless the panel is collapsible={false}, in which case the trigger is
disabled and no tooltip is shown at all, even if you pass an explicit
expandTooltip. extras is the same trailing slot as on a menu item, for a
shortcut hint.
The remaining structural parts (SidebarSecondaryContent,
SidebarSecondaryMenu, SidebarSecondaryFooter) accept the standard attributes
of the element they render.