Tooling
Recipes
Copy-ready patterns for common UI motion.
Each recipe uses only public STRX APIs. Adjust tokens to taste.
Staggered list entrance
1<Strx.Timeline playback="stagger" interval={50}>2 {items.map(item => (3 <Strx.View key={item.id} animate="fade-in from:translate-y-12 duration-260">4 <Row item={item} />5 </Strx.View>6 ))}7</Strx.Timeline>Keep the interval small (40–80ms) and the list short; for long lists, only stagger the first screenful.
Toast
1{toast && (2 <Strx.View3 animate="fade-in from:translate-y-24 spring damping-16, exit:opacity-0 exit:translate-y-24 duration-180 ease-in"4 style={styles.toast}5 >6 <Strx.Text>{toast.message}</Strx.Text>7 </Strx.View>8)}The entrance springs in; the exit, in its own group, has its own short timing.
Bottom sheet
1<Strx.View2 animate="from:translate-y-600 to:translate-y-0 spring damping-20 stiffness-180, exit:translate-y-600 duration-220 ease-in"3 style={styles.sheet}4>5 <SheetContent />6</Strx.View>Accordion
1<Strx.View animate="layout-spring" layoutClip style={styles.panel}>2 <Strx.Pressable onPress={() => setOpen(value => !value)}>3 <Strx.Text>{title}</Strx.Text>4 </Strx.Pressable>5 {open && <Strx.Text animate="fade-in exit:opacity-0 duration-150">{body}</Strx.Text>}6</Strx.View>Selectable chip
1<Strx.Pressable2 animate="transition-all duration-160"3 onPress={() => setSelected(!selected)}4 style={({ pressed }) => ({5 backgroundColor: selected ? "#3552f0" : "#f2f4f7",6 transform: [{ scale: pressed ? 0.96 : 1 }],7 })}8>9 <Strx.Text style={{ color: selected ? "#fff" : "#0b1020" }}>Design</Strx.Text>10</Strx.Pressable>Validation shake
Play a short keyframe animation from an event with useTimeline:
1const shake = Strx.useTimeline({2 playables: [{ target: "field", animate: "from:-translate-x-8 to:translate-x-0 spring damping-4 stiffness-400" }],3});45<Strx.TextInput strxId="field" onSubmitEditing={() => !valid && shake.play()} />;Pulsing indicator
1<Strx.View2 animate="from:opacity-40 to:opacity-100 from:scale-90 to:scale-100 duration-700 ease-in-out play-infinite"3 style={styles.dot}4/>Keep looping animations small. Under Reduce Motion they play once.
Skeleton to content
1{loading ? (2 <Strx.View animate="exit:opacity-0 duration-150" style={styles.skeleton} />3) : (4 <Strx.View animate="fade-in duration-250">5 <Content />6 </Strx.View>7)}Success screen
1const celebrate = Strx.useTimeline({2 playback: "stagger",3 interval: 90,4 playables: [5 { target: "badge", animate: "bounce" },6 { target: "headline", animate: "fade-in from:translate-y-12" },7 { target: "cta", animate: "fade-in from:translate-y-12" },8 ],9});1011useEffect(() => {12 if (paid) celebrate.play();13}, [paid]);Reorderable list
1<Strx.LayoutGroup transition="spring" damping={18}>2 {sorted.map(item => (3 <Strx.View key={item.id} animate="fade-in exit:opacity-0 exit:scale-95">4 <Row item={item} />5 </Strx.View>6 ))}7</Strx.LayoutGroup>When sorted changes order, rows spring to their new positions; removed rows fade out first.