Toggles
DownloadButton
Press it and the arrow drops, the tray flexes under the impact, then the arrow re-enters from above.
Usage
<DownloadButton
size="md"
dropDistance={7}
trayFlex={2.6}
intensity="normal"
spring="smooth"
/>How the motion works
The sequence is three coupled springs rather than a keyframed timeline: the arrow falls under a bouncy spring, the tray flexes and rebounds when the arrow arrives, and the arrow then returns from above. Driving the tray from the arrow's arrival — instead of running both on independent fixed delays — is what makes the impact read as a collision. The arrow fades as it sinks so it enters the tray rather than overlapping its stroke.
useSpringStateusePressuseReducedMotion
Limitations
Known gap. Impact timing uses a tuned delay rather than reading the arrow spring's position, because the fall and the flex are separate springs. Changing the fall spring to a much slower preset would desynchronise the impact.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| onDownload | () => void | — | Fires immediately on press, before the animation. |
| dropDistance | number | 7 | How far the arrow falls, in SVG units. |
| trayFlex | number | 2.6 | How far the tray bows on impact. |
| resetDelay | number | 220 | Pause before the arrow re-enters, in ms. |
