How to Spec Interactions for Developers
Spec interactions that developers can actually implement. Covers what devs need, minimum viable specs, animation tokens, Figma's Prototype tab, and ProtoPie handoff.
Most interaction specs fail in one of two ways: too much ambiguity ("make it feel smooth") or too much complexity (a 12-page motion spec nobody will read before shipping).
The goal is giving developers exactly what they need to implement the interaction accurately — no more, no less.
What developers need from interaction specs
Before writing specs, understand what your developers actually need to implement an interaction. The answers vary by team, but most developers need:
Timing: The duration in milliseconds. Not "fast" — 200ms.
Easing: The acceleration curve. "ease-in-out," "ease-out," or the specific cubic-bezier values if you're using something custom. Linear feels mechanical; most UI interactions need a curve.
Trigger: What initiates the animation. "On hover," "on click," "on focus," "after 300ms delay," "when prop isLoading becomes true."
Start state and end state: What does the element look like before, and what does it look like after? Both states should be clearly shown.
What's animating: Is the opacity changing? The scale? The position? Multiple properties? Be explicit. "Button fades out and label changes to checkmark" is clearer than "success state animation."
Stagger and sequencing: If multiple elements animate, do they all start simultaneously or is there a delay between each? "Each list item fades in with a 50ms stagger" needs to be specified — developers won't assume it.
The minimum viable spec
For most interactions, the minimum viable spec is an annotated Figma frame plus the motion values.
Create a documentation frame in your Figma file. For each interaction:
- Place the before state and after state side by side
- Add an annotation with the interaction spec: duration, easing, what's animating
- Link to a ProtoPie prototype for anything complex
That's it. This is genuinely sufficient for the majority of UI interactions.
Example annotation:
Button loading state On click: label fades out (opacity 1→0, 100ms, ease-in) and spinner fades in (opacity 0→1, 100ms, ease-out) with a 50ms delay On success: spinner fades out, checkmark scales in (scale 0.8→1, 200ms, ease-out)
A developer can implement that without asking any follow-up questions.
When to use a prototype instead of specs
Some interactions are too complex or too nuanced to communicate accurately with static specs. Prototype these.
Use a prototype when:
- The interaction involves multiple states with different behaviors
- The timing depends on content (a modal that scrolls to reveal more)
- There's conditional logic ("if the user has already dismissed this, don't show it again")
- The motion itself is important to the UX (not just a transition, but a functional animation like a drag-and-drop reorder)
A ProtoPie prototype that a developer can play and scrub through is worth more than three pages of written specs for complex interactions. It shows the motion directly rather than describing it.
Always include written specs alongside prototypes. Prototypes communicate the feel; specs give the implementable values.
Build interaction prototypes in ProtoPieDocumenting animation tokens
If your team ships multiple products or has a component library, define animation tokens. These are named design decisions that everyone references consistently — the same way you use color tokens.
A minimal animation token set:
Duration:
duration-fast: 100ms — hover states, immediate feedbackduration-base: 200ms — most UI transitionsduration-slow: 300ms — larger layout changes, modalsduration-emphasis: 500ms — deliberate attention-directing animations
Easing:
ease-standard: cubic-bezier(0.4, 0, 0.2, 1) — general purposeease-enter: cubic-bezier(0, 0, 0.2, 1) — elements entering the screenease-exit: cubic-bezier(0.4, 0, 1, 1) — elements leavingease-sharp: cubic-bezier(0.4, 0, 0.6, 1) — quick snappy transitions
In CSS, these become custom properties: --duration-base: 200ms and --ease-standard: cubic-bezier(0.4, 0, 0.2, 1). Developers use them directly in their CSS transitions and animations. When you want to update the base duration globally, one value change propagates everywhere.
Document your animation tokens in Figma's plugin panel if you're using a token plugin, or as a dedicated tokens page in your design file. Keep them alongside your color and typography tokens.
Using Figma's Prototype tab to communicate intent
Figma's built-in Prototype tab is sufficient for documenting simple interactions. Connect frames with transitions and configure:
- Trigger type (on click, on hover, while hovering, on drag)
- Animation type (instant, dissolve, smart animate, move in/out, push)
- Easing
- Duration
"Smart Animate" in Figma interpolates between frames by matching layer names. This is useful for demonstrating micro-interactions without full prototyping tools — a button that transitions between default, hover, and loading states in Figma's prototype can demonstrate the animation values you intend even if the actual motion doesn't need to be pixel-perfect.
In Figma Dev Mode, developers can inspect prototype connections and see the animation properties you set. This means your Figma prototype isn't just for stakeholder reviews — it's directly useful for implementation.
Handing off ProtoPie prototypes
When the interaction is specified in ProtoPie, share the prototype via ProtoPie's cloud share link. Developers can play the prototype and inspect properties.
ProtoPie's Inspect view shows developers the trigger, response, and animation values directly. This is especially useful for conditional interactions and multi-state animations that can't be expressed in static specs.
Include in your handoff documentation:
- Link to the ProtoPie prototype
- Written motion values (don't make developers derive values by watching the animation)
- Any interaction that depends on real data or states (ProtoPie prototypes use mock data; make the real-data behavior explicit)
What to leave out of specs
Pixel-level perfection for low-visibility transitions. The difference between 190ms and 200ms is not perceptible. Don't over-specify values that don't matter.
Interactions that aren't your call to make. If the engineering team is using a component library with pre-built animation behaviors (Material UI, shadcn), some transitions are already defined. Spec the interactions you're changing, not the ones the library handles.
Specs for interactions you haven't validated. If you haven't prototyped an interaction and confirmed it works, don't write a formal spec yet. Specs that change constantly erode developer trust.
The best interaction spec leaves no ambiguous questions. Read your spec from a developer's perspective before handing it off: after reading this, would I know exactly what to build?
Related
How to Hand Off Designs to Developers
Developer handoff best practices — Figma Dev Mode, layer naming, specifying interactions and states, and when to use Zeplin vs Dev Mode.
How to Design Micro-Interactions
Design micro-interactions that communicate, not just decorate. Covers triggers, feedback loops, timing guidelines, and how to prototype with ProtoPie and Principle.
Zeplin vs Figma Dev Mode: Do You Still Need Zeplin?
Figma Dev Mode does most of what Zeplin used to do — and it's included in your Figma plan. Here's when Zeplin is still worth keeping.