Accordion
Code
| 1 | // <AnimeLayout> FLIP-animates the panel height. On toggle, update() |
| 2 | // commits the new state (via flushSync), measures the before/after height |
| 3 | // delta, and tweens it — no manual measurement or raw animate(). |
| 4 | const AccordionItem = ({ title, body, isOpen, onToggle }) => { |
| 5 | const layoutRef = useRef(null) |
| 6 | |
| 7 | const handleToggle = () => { |
| 8 | layoutRef.current?.update( |
| 9 | () => flushSync(() => onToggle()), |
| 10 | { duration: 320, ease: 'outExpo' }, |
| 11 | ) |
| 12 | } |
| 13 | |
| 14 | return ( |
| 15 | <div className="overflow-hidden rounded-lg border"> |
| 16 | <button onClick={handleToggle} aria-expanded={isOpen}>{title} ▼</button> |
| 17 | <AnimeLayout |
| 18 | ref={layoutRef} |
| 19 | mode="manual" |
| 20 | duration={500} |
| 21 | ease="outExpo" |
| 22 | enterFrom={{ opacity: 0 }} |
| 23 | leaveTo={{ opacity: 0 }} |
| 24 | > |
| 25 | {isOpen && ( |
| 26 | <AnimeLayout.Item key="panel" layoutId="panel"> |
| 27 | {body} |
| 28 | </AnimeLayout.Item> |
| 29 | )} |
| 30 | </AnimeLayout> |
| 31 | </div> |
| 32 | ) |
| 33 | } |
Expand/collapse panels with height animation and single/multi open modes.
Live preview
AccordionClick a header to toggle
A React wrapper around anime.js v4 — hooks-first, with declarative components where they help.
Props
| Name | Type | Default | Description |
|---|---|---|---|
| mode | 'manual'|'auto' | 'manual' | manual = call update() to trigger FLIP; auto = animate on children change |
| update | (cb, params) => Timeline | - | Records layout, runs cb (flushSync), animates the delta |
| enterFrom | CSSProperties | {opacity:0} | Initial state for entering content |
| leaveTo | CSSProperties | {opacity:0} | Final state for leaving content |
| duration | number | 500 | Layout transition ms (update override uses 320) |