One engine, four behaviours. Headers are real buttons with aria-expanded,
panels are labelled regions, and every panel height is a measured pixel value —
no max-height guesswork, so long content never clips and short content
never drags. Open panels park at height:auto, so they survive a resize.
Press H to hide the control panel.
Every row keeps its own state, so a reader can leave several answers open side by side. Chevron flips 180°.
Drop in the script, mark up your rows, then call init on the wrapper.
Nothing else loads and nothing else runs.
No. It is one plain script with no imports, so it runs from a file path as happily as from a server.
The shared tween core is optional — the engine ships a small fallback and
uses window.FX only when it finds it.
Yes. Set multi to true. Leave it false and opening one row closes
the row that was open, with the same timing.
Each header becomes a real button carrying aria-expanded and
aria-controls; each panel is a region labelled by its header.
Closed panels are hidden, so their links stay out of the tab order.
The FAQ pattern: opening a row closes the last one. Icon rotates 45° into a cross; switch it to the two-stroke plus-to-x morph in the panel.
A max-height guess either clips long content or spends half the
tween animating empty space. Measuring the panel gives the tween an exact
target, so the timing you set is the timing you get.
When the open tween finishes, the panel is parked at height:auto.
It then reflows with the page — text can rewrap to three lines and the row
grows with it.
Call open(i), close(i) or toggle(i)
with the row index. closeAll() and openAll() are
there too, and onToggle fires on every state change.
Yes. When the system asks for less motion, rows snap open and shut with no tween, no FLIP and no flicker. The state and the aria wiring are unchanged.
A portfolio row. Opening reveals a description and action pills, and the thumbnail strip FLIPs into a full-size media row. Media here is plain gradient boxes — swap them for images or video.
A ferry operator with twelve routes and no shared visual language. We built one mark, one type scale and a booking flow that reads the same on a pier sign and on a phone.
Trade catalogue, 4,000 parts, printed twice a year. We cut the page count by a third by fixing the grid and the naming, then took the same system to the shelf.
A workshop that had outgrown its market stall. The site leads with the making, not the shop, and the shop follows.
Rows open under the pointer: the pixel mark flickers, the title nudges right, a hairline draws in from the left and the panel reveals a media block. With no hover pointer — touch — the same rows fall back to tap, and the keyboard path is unchanged.
Six to ten weeks. A mark, a type scale and the rules that keep them honest once other people start using them.
Screens first, tokens after. We draw the hard screens before the library, so the library answers real questions.
Motion with a job. Every move either shows where something came from or where it went.
No framework tax. Plain scripts, measured values, and a page that still works when a script fails to load.