Sidebar Toggle
Icon sidebar with a chevron button: expanded, it goes from 80 to 160 px, names its links, and the content beside it rearranges itself.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →
3 usage examples



How it works
The .fx-0752-root element holds a .csb-scene row: on the left the <nav class="csb-panel"> (the .csb-toggle button, then one .csb-item link per entry), on the right the .csb-main area. The button adds or removes the is-expanded class on the bar and updates its aria-expanded; the width goes from 80 to 160 px in 0.4 s and the chevron turns half a turn.
The bar is itself a container (container: csb-panel / inline-size). Collapsed, its usable width is 67 px: the .csb-text labels are hidden from sight but still read, and the icons are centred. From 100 usable px (so once expanded), @container csb-panel (min-width: 100px) shows the labels and left-aligns the links. The bar's width decides, not the button state: if you force a 120 px width in CSS, the labels show too.
The main area is a second container (csb-main): its .csb-block tiles (a .csb-num figure and its .csb-cap caption) sit in one column below 180 px and in two from 180 px. When the bar expands, the content loses 80 px and rearranges itself. The script attaches to each root, once, with no id: two copies on one page open independently.
Accessibility
- Announced button: a real
<button type="button">named “Show menu labels”, witharia-expandedset tofalseortrue; Enter and Space activate it. - Links named even when collapsed: labels are hidden from sight (1 px box), not removed; a screen reader reads “Projects, link” in the 80 px bar. Icons carry
aria-hidden="true". - Current page:
aria-current="page"on the active link, moved on click by the script. - Visible focus: 2 px
#a78bfaoutline on the button and the links. In Safari, Tab only stops on links with Option+Tab or the macOS keyboard setting. - Reduced motion: under
prefers-reduced-motion: reduce, the bar changes width at once and the chevron flips without rotating; opening works exactly the same.
Browser compatibility
Container queries (Chrome 105, Firefox 110, Safari 16) and :focus-visible (Safari 15.4). Measured in Chromium 151, Firefox 153 and WebKit 26.5 with two copies on one page: the 2nd copy's button opens only the 2nd (80 → 160 px, aria-expanded="true", 36 to 49 px labels visible), keyboard and touch included; tiles in 2 columns from 180 px of content; 0 errors.
Without container queries, the button still widens the bar but labels stay hidden from sight (screen readers still read them) and the tiles stay in one column. Without JavaScript, the bar stays collapsed.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0752-root">
<div class="csb-scene">
<nav class="csb-panel" aria-label="…">
<button type="button" class="csb-toggle" aria-expanded="false" aria-label="…">…</button>
<a class="csb-item" href="#…" aria-current="page">
<svg aria-hidden="true">…</svg>
<span class="csb-text">…</span>
</a>
</nav>
<div class="csb-main">
<p class="csb-title">…</p>
<div class="csb-blocks">
<div class="csb-block"><span class="csb-num">…</span><span class="csb-cap">…</span></div>
</div>
</div>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Widths (CSS — .csb-panel and .csb-panel.is-expanded) |
80 px collapsed, 160 px expanded | Keep the collapsed width below the label breakpoint and the expanded width above it. |
Label breakpoint (CSS — @container csb-panel (min-width: 100px)) |
100 px of usable width | Raise it if you widen the collapsed bar (otherwise labels would show from the start). |
Content breakpoint (CSS — @container csb-main (min-width: 180px)) |
Tiles in 1 column, then 2 from 180 px | Add more breakpoints on csb-main for your own content (table, cards). |
State on load (HTML — is-expanded class on .csb-panel) |
Collapsed | Add the class to start expanded; the script aligns aria-expanded on load. |
Entries (HTML — .csb-item) |
Home, Projects, Settings | One link per entry with its SVG icon and its .csb-text; aria-current="page" on the current page. |
| Colours (CSS) | Button rgba(139,92,246,.2) and chevron #8b5cf6, active link rgba(139,92,246,.2) |
Replace them on .csb-toggle, .csb-toggle svg and .csb-item[aria-current]. |
Duration (CSS — transition: width .4s on .csb-panel) |
0.4 s; chevron 0.3 s | Shorten or remove the transition; reduced motion already removes it. |
FAQ
@container rule shows the labels once the bar exceeds 100 usable px. A bar widened any other way (CSS, another script) shows them too.localStorage) and put the is-expanded class on .csb-panel on load: the script then syncs aria-expanded.