
The tile mega menu
Menus, Hover, 3D, Transitions
NewFree
The light sidebar of a dashboard with a button to fold it: every name closes in a concertina behind its icon like a strip of paper, one after the other from the top, while the bar narrows to its icons. Folded, pointing at an icon unfolds its name beside it in a little tag.
A folder that runs on its own: index.html, style.css, script.js and the libraries from a CDN. The React and Vue tabs hold the same demo as a ready component, which switches its animations off when it leaves the page.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>The folding sidebar</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geist@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the sidebar of a dashboard: the button at the top folds it down to its icons, and every name folds away behind
its icon like a strip of paper closing in a concertina, one after the other from the top; folded, the name of an
icon pointed at unfolds beside it as a little tag -->
<div class="fs-wrap" data-wrap>
<nav class="fs" aria-label="Main" data-nav data-autoclic>
<div class="fs__head">
<button class="fs__toggle" type="button" aria-expanded="true" aria-controls="fs-list" aria-label="Collapse sidebar" data-toggle>
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="4" width="18" height="16" rx="3"/><path d="M9 4V20"/><path class="fs__chev" d="M15.5 9.5L13 12L15.5 14.5"/></svg>
</button>
</div>
<div class="fs__body" data-body>
<span class="fs__mark" aria-hidden="true" data-mark></span>
<ul class="fs__list" id="fs-list">
<li><a class="fs__item" href="#" aria-current="page" data-item>
<svg class="fs__icon" viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="3.5" width="7" height="7" rx="2"/><rect x="13.5" y="3.5" width="7" height="7" rx="2"/><rect x="3.5" y="13.5" width="7" height="7" rx="2"/><rect x="13.5" y="13.5" width="7" height="7" rx="2"/></svg>
<span class="fs__label" data-label>Overview</span></a></li>
<li><a class="fs__item" href="#" data-item>
<svg class="fs__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 7.5A2 2 0 0 1 5 5.5H9.5L11.5 7.5H19A2 2 0 0 1 21 9.5V17.5A2 2 0 0 1 19 19.5H5A2 2 0 0 1 3 17.5Z"/><path d="M3 10.5H21"/></svg>
<span class="fs__label" data-label>Projects</span></a></li>
<li><a class="fs__item" href="#" data-item>
<svg class="fs__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 6.5A2.5 2.5 0 0 1 6.5 4H17.5A2.5 2.5 0 0 1 20 6.5V14A2.5 2.5 0 0 1 17.5 16.5H10.5L6.5 20V16.5A2.5 2.5 0 0 1 4 14Z"/><path d="M8 9H16M8 12.5H13"/></svg>
<span class="fs__label" data-label>Messages</span>
<span class="fs__badge" data-badge>4<span class="fs__sr"> unread</span></span></a></li>
<li><a class="fs__item" href="#" data-item>
<svg class="fs__icon" viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="5" width="17" height="15.5" rx="2.5"/><path d="M3.5 9.5H20.5M8 3V6.5M16 3V6.5"/></svg>
<span class="fs__label" data-label>Calendar</span></a></li>
<li><a class="fs__item" href="#" data-item>
<svg class="fs__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 20H20"/><path d="M7 16.5V11M12 16.5V6.5M17 16.5V13.5"/></svg>
<span class="fs__label" data-label>Reports</span></a></li>
<li><a class="fs__item" href="#" data-item>
<svg class="fs__icon" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5.1L13.76 3.17L15.44 3.69L15.83 6.26L16.88 7.12L19.48 7L20.31 8.56L18.77 10.65L18.9 12L20.83 13.76L20.31 15.44L17.74 15.83L16.88 16.88L17 19.48L15.44 20.31L13.35 18.77L12 18.9L10.24 20.83L8.56 20.31L8.17 17.74L7.12 16.88L4.52 17L3.69 15.44L5.23 13.35L5.1 12L3.17 10.24L3.69 8.56L6.26 8.17L7.12 7.12L7 4.52L8.56 3.69L10.65 5.23Z"/><circle cx="12" cy="12" r="2.8"/></svg>
<span class="fs__label" data-label>Settings</span></a></li>
</ul>
</div>
</nav>
<!-- the name of an icon pointed at while the bar is folded: a little tag that unfolds beside it -->
<span class="fs__tip" aria-hidden="true" data-tip></span>
</div>
</main>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.15.0/dist/gsap.min.js"></script>
<script src="script.js"></script>
</body>
</html>Change values, colours and text with the controls and watch the animation respond live. Or write in the code yourself. Then download the folder with your changes.
24 values to change
With the Animorio connector, Claude Code takes it from here, guide included, and fits it into your project. Paste this request:
Take “The folding sidebar” from Animorio and fit it into my siteThe script reads each row's name, measures it and builds PANELS panels a third wide each: every panel shows its slice of the whole word (the same text shifted left by k times the width) and holds the next panel on its right edge, so turning one carries all those after it. The real name stays in the link, hidden from sight, for screen readers.
With q from 0 (flat) to 1 (closed) the angle is a = 88° · q: the first panel turns by +a with rotateY on its left hinge, the second by −2a against the first, the third by +2a, so they lie at +a, −a, +a and the strip is w·cos(a) wide. Each panel has its row's ground and a gradient veil that grows with the sine of the angle, dark for those turned away from the light and pale for the others; over the last few degrees the strip fades, so it leaves no edge-on hairlines.
Each row has its own q, animated by a single gsap.to with a STAGGER-second stagger, from the top both ways. Every frame the bar's width is SHUT + (OPEN − SHUT) times the largest cosine among the rows, so it follows the most open name and never cuts one; the ground under the page chosen and the badge are worked out from the same width, the badge sliding towards the icon's corner with its row's q.
Folded, the name of the icon pointed at or reached with Tab is cut into the same panels inside a dark tag beside the bar, which unfolds from q = 1 to 0 in TIP_FOLD seconds with back.out; its point only shows once the tag is nearly open. Moving to another icon it folds shut, moves down and unfolds again; Esc closes it, and with a tap it stays out for a second and a half.
The ground under the page chosen goes to its row in SLIDE seconds, stretching by 18% from the side it leaves and gathering itself with back.out on arrival. The button has aria-expanded, aria-controls and a label saying what it will do; the links have aria-current. The library's preview takes a tour: it chooses, folds, shows a tag, opens again.
| Name | File | Default | What it changes |
|---|---|---|---|
PANELS | script.js | 3 | How many panels each name folds into. |
FOLD | script.js | 0.62 | The seconds one name takes to fold or unfold. |
STAGGER | script.js | 0.06 | The seconds between one name and the next, from the top. |
TIP_FOLD | script.js | 0.42 | The seconds the tag beside a folded icon takes to unfold. |
SLIDE | script.js | 0.45 | The seconds the ground under the page chosen takes to slide there. |
For the sidebar of a dashboard, a back office, a project or messaging app, an admin panel: anywhere the content needs room without losing the navigation.
The open bar is 236 pixels wide and fits on screen together with the tag; every row is 44 pixels tall. Folded, tapping an icon chooses the page and brings out its name for a second and a half.
No folds and no sliding: the names and the tag fade in and out, the bar takes its width at once and the ground under the page chosen jumps to its row.
GSAP 3.15.0, Geist (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 7.9 KB; the libraries: GSAP 28 KB.
Tested on 5 October 2026
Use it in your own projects and in your clients’ projects. Do not resell it or redistribute it as is. GSAP stays under its own Standard license. Full license.
With your account’s email and password.
or with your email
You’re signed in as .
With your account, you can download the zip of every animation and every pack, for free.