Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Created January 14, 2026 20:58
Show Gist options
  • Select an option

  • Save ryanflorence/37288d8f017a88753ba57c5ec52596bf to your computer and use it in GitHub Desktop.

Select an option

Save ryanflorence/37288d8f017a88753ba57c5ec52596bf to your computer and use it in GitHub Desktop.
function StaggeredList(handle: Handle) {
let items = ['Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon']
let visible = false
function toggle() {
visible = !visible
handle.update()
}
// Calculate total animation duration
// Items stagger at 50ms each, plus 300ms for the last item's animation
let totalDuration = (items.length - 1) * 50 + 300
return () => {
// Opening: height animates twice as fast
// Closing: height syncs with stagger
let heightDuration = visible ? totalDuration / 2 : totalDuration
return (
<div
css={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '24px',
}}
>
<button
on={{ click: toggle }}
css={{
backgroundColor: '#9911ff',
color: 'white',
border: 'none',
borderRadius: '8px',
padding: '12px 24px',
fontSize: '14px',
fontWeight: '500',
cursor: 'pointer',
transition: 'transform 0.1s',
'&:active': {
transform: 'scale(0.95)',
},
}}
>
{visible ? 'Hide' : 'Show'} List
</button>
{/* Grid container for height animation (0fr → 1fr technique) */}
<div
css={{
display: 'grid',
}}
style={{
gridTemplateRows: visible ? '1fr' : '0fr',
transition: `grid-template-rows ${heightDuration}ms cubic-bezier(0.4, 0, 0.2, 1)`,
}}
>
{/* Inner wrapper must have overflow:hidden and min-height:0 */}
<div
css={{
overflow: 'hidden',
minHeight: '0',
'& *:last-child': {
marginBottom: '1rem',
},
}}
>
<ul
css={{
listStyle: 'none',
padding: '0',
margin: '0',
display: 'flex',
flexDirection: 'column',
gap: '8px',
width: '200px',
}}
>
{items.map((item, index) => (
<li
key={item}
css={{
backgroundColor: 'white',
padding: '16px',
borderRadius: '8px',
textAlign: 'center',
color: '#0f1115',
fontWeight: '500',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
// Staggered enter animation
transition: 'opacity 0.3s ease-out, transform 0.3s ease-out',
}}
style={{
opacity: visible ? 1 : 0,
transform: visible ? 'translateY(0)' : 'translateY(20px)',
transitionDelay: visible
? `${index * 50}ms`
: `${(items.length - 1 - index) * 50}ms`,
}}
>
{item}
</li>
))}
</ul>
</div>
</div>
</div>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment