
The cookie banner
Consent, Transitions, SVG, Physics
NewFree
The questions of an open-air pool sit on a single card the colour of water. Opening one, the card tears along both edges of its row like a liquid: the slits run in from the sides, the last thread snaps into two drops that sink back into the edges, and the piece comes away and stretches down over the answer. Closed again, the pieces reach for each other, touch, and the seam zips shut out to the sides.
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 pull-apart accordion</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fontsource-variable/geologica@5.3.0/index.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<main class="stage">
<!-- the questions of an open-air pool. At rest they are one card; opening a question, the card tears along both
edges of its row like a liquid, the row comes away as a piece of its own and stretches down to show the
answer. The card is a single path the script draws behind the rows -->
<div class="faq" data-faq>
<svg class="faq__shape" aria-hidden="true" focusable="false">
<defs>
<linearGradient id="faq-water" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="600" data-gradient>
<stop offset="0" class="faq__stop-top"/>
<stop offset="1" class="faq__stop-deep"/>
</linearGradient>
<filter id="faq-lift" x="-20%" y="-20%" width="140%" height="150%" color-interpolation-filters="sRGB">
<feDropShadow class="faq__shadow-far" dx="0" dy="14" stdDeviation="14"/>
<feDropShadow class="faq__shadow-near" dx="0" dy="2" stdDeviation="1.5"/>
</filter>
<filter id="faq-float" x="-30%" y="-40%" width="160%" height="220%" color-interpolation-filters="sRGB">
<feGaussianBlur in="SourceAlpha" stdDeviation="14"/>
<feOffset dy="16" result="soft"/>
<feFlood class="faq__float"/>
<feComposite in2="soft" operator="in"/>
</filter>
</defs>
<g filter="url(#faq-float)" data-lifts></g>
<path class="faq__body" fill="url(#faq-water)" filter="url(#faq-lift)" data-body/>
<g data-seams></g>
</svg>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q1" aria-expanded="false" aria-controls="faq-a1"><span class="faq__text">Do I need to book?</span><svg class="faq__chev" viewBox="0 0 16 10" aria-hidden="true"><path/></svg></button></h3>
<div class="faq__a" id="faq-a1" role="region" aria-labelledby="faq-q1" hidden><div class="faq__inner"><p>Lanes go in 45-minute sessions you can book up to a week ahead. If a lane is free you can just walk in: the board by the gate shows which ones.</p></div></div>
</div>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q2" aria-expanded="false" aria-controls="faq-a2"><span class="faq__text">Is the water heated?</span><svg class="faq__chev" viewBox="0 0 16 10" aria-hidden="true"><path/></svg></button></h3>
<div class="faq__a" id="faq-a2" role="region" aria-labelledby="faq-q2" hidden><div class="faq__inner"><p>All year round: 25 degrees in the long pool and 30 in the shallow one. On cold mornings the steam rising off the water is half the fun.</p></div></div>
</div>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q3" aria-expanded="false" aria-controls="faq-a3"><span class="faq__text">What should I bring?</span><svg class="faq__chev" viewBox="0 0 16 10" aria-hidden="true"><path/></svg></button></h3>
<div class="faq__a" id="faq-a3" role="region" aria-labelledby="faq-q3" hidden><div class="faq__inner"><p>A swim cap, a coin for the lockers and a towel, or borrow one at the desk. Flip-flops help on the deck when the tiles are cold.</p></div></div>
</div>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q4" aria-expanded="false" aria-controls="faq-a4"><span class="faq__text">Can kids swim alone?</span><svg class="faq__chev" viewBox="0 0 16 10" aria-hidden="true"><path/></svg></button></h3>
<div class="faq__a" id="faq-a4" role="region" aria-labelledby="faq-q4" hidden><div class="faq__inner"><p>From eight years old, after a short swim test at the desk. Younger children swim with an adult, one grown-up for every two children.</p></div></div>
</div>
<div class="faq__item" data-item>
<h3 class="faq__head"><button class="faq__q" type="button" id="faq-q5" aria-expanded="false" aria-controls="faq-a5"><span class="faq__text">What if it storms?</span><svg class="faq__chev" viewBox="0 0 16 10" aria-hidden="true"><path/></svg></button></h3>
<div class="faq__a" id="faq-a5" role="region" aria-labelledby="faq-q5" hidden><div class="faq__inner"><p>We clear the water at the first rumble of thunder and wait half an hour after the last one. Your session goes straight back into your account.</p></div></div>
</div>
</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.
26 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 pull-apart accordion” from Animorio and fit it into my siteThe card is a single SVG path rebuilt on every frame from the positions of the rows. Each group of rows still joined is a subpath: it goes down the right side and, at every seam that is tearing, into the slit (corner arc, straight edge, half an ellipse for the tip, straight edge, corner arc); then it goes back up the left side doing the same. The questions are absolutely placed buttons that only move with translate3d; each answer is cut by a clip-path inset at the bottom of its piece. While it moves, the page is never laid out again.
How much of each answer shows and each gap between two rows are springs, with stiffness and damping worked out from a duration and a bounce as Apple describes them (OPEN and BOUNCE; the gaps get a quicker spring). The top of each row is the bottom of the one above plus the gap between them: the pieces below make room by themselves and never overlap, even when a spring goes past. The sums are done in steps of 1/240 of a second, with the frame step capped at 1/30.
A GSAP tween takes the tear's progress from 0 to 1 with power2.in, slow at first and then all at once, in TEAR seconds. Each slit is that fraction of the distance from its side to the meeting point (where the question was pressed; the middle for the keyboard), and its tip is half an ellipse as tall as the gap: when the two tips touch, the neck is zero wide. At 1 there are two pieces, each with its torn end: a bump made of two Bézier curves, 62 per cent of the gap tall, that sinks back on a spring set by WOBBLE while the gap gets a kick.
Closing, when the gap drops under 60 per cent of GAP the two ends stretch towards each other; when they touch the seam is whole again with the slits reaching the meeting point, and a power3.out tween takes them back to the sides in 0.36 seconds. Everything can be interrupted: opening again halfway, the tween turns round and the slit starts from where it is.
The thin lines are only drawn on the bridge of water that is left and fade as the tear runs. The card has two feDropShadows; the open piece also has a shadow of its own, a narrower rectangle blurred and moved down, that grows with the answer. The loop runs on GSAP’s ticker only while something moves. The questions are buttons inside an h3 with aria-expanded and aria-controls, the answers regions that are hidden when closed; arrows, Home and End go from one question to another. The question after the open one has data-autoclic for the preview.
| Name | File | Default | What it changes |
|---|---|---|---|
FIRST | script.js | 1 | The question open when the page opens, from 0; −1 for none. |
ONLY_ONE | script.js | true | Opening a question closes the open one; with false many can be open. |
GAP | script.js | 16 | The room between two pieces of card that have come apart, in pixels. |
OPEN | script.js | 0.62 | The seconds an answer takes to open or close. |
BOUNCE | script.js | 0.14 | How far the answers and the pieces go past their place and come back (0 not at all). |
TEAR | script.js | 0.42 | The seconds the tear takes to run across the card. |
WOBBLE | script.js | 0.6 | How much a torn end wobbles as it sinks back into its edge (0 not at all). |
HINT | script.js | 8 | How deep the card pinches at the edges of the question under the mouse, in pixels; 0 not at all. |
ROUND | script.js | 22 | The radius of the card’s corners, in pixels. |
For the frequently asked questions of a service, a venue or an app, for the terms of a membership or the sections of a product sheet: wherever there are many answers and one is read at a time, and the site has a soft, fresh or playful character. The piece that has come away shows at a glance which answer is open, even from afar.
The card is at most 640 pixels wide and on a phone narrows to the screen, with a 16 pixel margin each side (358 on a 390 phone). Closed rows are 80 pixels tall on a computer and 72 on a phone, as in the library’s other accordion, and the questions go down to 17 pixels. A finger pressing a question makes the card pinch at its edges as the mouse over it does, and the tear runs towards the point touched.
No tear and no movement: the card splits and closes again at once, already in place, and the answer’s text fades in. When the page opens the card fades in with the second question already open; no drops flowing together and no pinch under the mouse.
GSAP 3.15.0, Geologica (font variabile) 5.3.0.
Compressed with gzip, the three demo files weigh 9.2 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.