---
title: Motion
description: Appetite UI motion tokens for Figma: five durations, five easing curves, three springs and seven presets, with the timing of 14 components.
group: Foundations
source: https://www.appetiteui.com/docs/motion
dateModified: 2026-10-15
---

# Motion

Updated: October 15, 2026.

Five durations, five curves and three spring configurations. Seven presets alias them, so a sheet, a dialog and a toast move the same way in every screen and in the code.

## How long should a transition take?

120 ms for a small state change, 200 ms for a sheet, a dialog or a page push, 320 ms for progress and 480 ms for a skeleton loop. Click a row to run that one on its own.

Figure: the motion tokens in group 0, played on a track.

| Token | Value, ms | Used by |
| --- | --- | --- |
| `motion/duration/instant` | 0 | No component |
| `motion/duration/fast` | 120 | Sheet exit, toast enter, toggle state, Table sort, Spinner steps |
| `motion/duration/base` | 200 | Sheet enter, dialog enter, page push, Segmented Control, Tabs, Typing Indicator |
| `motion/duration/slow` | 320 | Progress Bar, Progress Ring |
| `motion/duration/slower` | 480 | Skeleton pulse |

No preset reads instant. Progress Bar and Progress Ring read slow directly, so a component can name a duration without a preset, and the Components section below lists who reads what.

## Which easing curve fits which movement?

Decelerate for what enters, accelerate for what leaves, standard for small changes that stay put, emphasized for hero moves and linear for loops. Duration says how long, easing says where the time goes.

Figure: the motion tokens in group 1, played on a track.

| Token | Value | Used by |
| --- | --- | --- |
| `motion/easing/linear` | cubic-bezier(0, 0, 1, 1) | Skeleton pulse, Spinner, Typing Indicator |
| `motion/easing/standard` | cubic-bezier(0.2, 0, 0, 1) | Toggle state, Segmented Control, Tabs, Table sort |
| `motion/easing/decelerate` | cubic-bezier(0, 0, 0, 1) | Sheet enter, toast enter |
| `motion/easing/accelerate` | cubic-bezier(0.3, 0, 1, 1) | Sheet exit |
| `motion/easing/emphasized` | cubic-bezier(0.05, 0.7, 0.1, 1) | Dialog enter, page push, Progress Bar, Progress Ring |

decelerate and accelerate are a pair: a thing arriving slows into place, a thing leaving speeds away. emphasized is the steepest curve off the line, with about 78 percent of the distance covered in the first fifth of the time and then a long settle, which is why it carries the dialog and the page push. Never use linear for an entrance.

## How do the three springs behave?

Three configurations, stated as response, damping and mass. Native code takes them as springs; on the web, sample the spring into a CSS linear() curve and run it over its response.

| Token | Response | Damping | Mass |
| --- | --- | --- | --- |
| `motion/spring/subtle` | 0.30 | 0.90 | 1.0 |
| `motion/spring/default` | 0.40 | 0.80 | 1.0 |
| `motion/spring/bouncy` | 0.50 | 0.65 | 1.0 |

subtle carries motion/toast/enter and motion/toggle/state. default carries motion/sheet/enter and motion/dialog/enter.

bouncy is referenced by no preset, so it is there for a component that asks for it directly. Mass is 1.0 on all three, and response and damping are the only two things that move.

A spring on the web, motion/spring/subtle as CSS linear().

```
/* motion/spring/subtle: response 0.30, damping 0.90.
   Run it over its response, 300 ms. */
.toggle-handle {
  transition: transform 300ms linear(
    0, 0.0419 3.57%, 0.139 7.14%, 0.2596 10.71%,
    0.3843 14.29%, 0.5017 17.86%, 0.606 21.43%, 0.695 25%,
    0.7685 28.57%, 0.8277 32.14%, 0.8742 35.71%, 0.9101 39.29%,
    0.9372 42.86%, 0.9573 46.43%, 0.9719 50%, 0.9822 53.57%,
    0.9894 57.14%, 0.9943 60.71%, 0.9975 64.29%, 0.9995 67.86%,
    1.0006 71.43%, 1.0012 75%, 1.0015 78.57%, 1.0015 82.14%,
    1.0014 85.71%, 1.0012 89.29%, 1.0011 92.86%, 1.0009 96.43%,
    1
  );
}
```

The curve is the spring the Figma file plays, sampled at 29 points. subtle peaks at 1.0015 and default overshoots to 1.0152, which is the settle of a sheet or a dialog; the animated components below run both this way.

## Which motion presets does the kit ship?

Seven presets, every one an alias. A preset holds no value of its own, it points at a duration, a curve and, where the platform can spring, a spring.

Figure: the motion tokens in group 2, played on a track.

| Preset | Duration | Easing | Spring |
| --- | --- | --- | --- |
| `motion/sheet/enter` | base | decelerate | default |
| `motion/sheet/exit` | fast | accelerate | None |
| `motion/dialog/enter` | base | emphasized | default |
| `motion/toast/enter` | fast | decelerate | subtle |
| `motion/toggle/state` | fast | standard | subtle |
| `motion/page/push` | base | emphasized | None |
| `motion/skeleton/pulse` | slower | linear | None |

There is no motion/dialog/exit. Sheet ships both directions and dialog ships only enter, so the exit of a dialog has no token yet.

A Figma variable cannot hold an animation preset, so each preset here ships as separate variables: `motion/sheet/enter/duration`, `motion/sheet/enter/easing` and `motion/sheet/enter/spring`. You do not apply them from Figma's animation panel. A component binds them, and code reads them as tokens. For movement you can place, use the animated components below.

## Which components move, and how?

The 14 components that move each name the preset they take their timing from, so retiming a preset retimes every component that reads it.

Figure: the motion tokens in group 3, played on a track.

| Component | Trigger | Preset | Timing |
| --- | --- | --- | --- |
| [Accordion](https://www.appetiteui.com/docs/accordion) | Click | `motion/duration/base` | 200 ms, ease out |
| [Button](https://www.appetiteui.com/docs/button), loading | Loop | `motion/skeleton/pulse` | 600 ms, ease in out |
| [Checkbox](https://www.appetiteui.com/docs/checkbox) | Click | `motion/toggle/state` | 120 ms, standard |
| [Dynamic Island](https://www.appetiteui.com/docs/ios) | Press | `motion/dialog/enter` | 320 ms, emphasized |
| [Progress Bar](https://www.appetiteui.com/docs/progress) | Loop | `motion/duration/slow` | 320 ms, emphasized, 600 ms dwell |
| [Progress Ring](https://www.appetiteui.com/docs/progress) | Loop | `motion/duration/slow` | 320 ms, emphasized, 600 ms dwell |
| [Radio](https://www.appetiteui.com/docs/radio) | Click | `motion/toggle/state` | 120 ms, standard |
| [Segmented Control](https://www.appetiteui.com/docs/segmented-control) | Click | `motion/duration/base` | 200 ms, standard |
| [Skeleton](https://www.appetiteui.com/docs/skeleton) | Loop | `motion/skeleton/pulse` | 480 ms, linear |
| [Spinner](https://www.appetiteui.com/docs/progress) | Loop | `motion/duration/fast` | 80 ms per step, linear, 8 steps |
| [Table](https://www.appetiteui.com/docs/table), sort | Press | `motion/duration/fast` | 120 ms, standard |
| [Tabs](https://www.appetiteui.com/docs/tab) | Click | `motion/duration/base` | 200 ms, standard |
| [Toggle](https://www.appetiteui.com/docs/toggle) | Click | `motion/toggle/state` | 120 ms, standard |
| [Typing Indicator](https://www.appetiteui.com/docs/progress) | Loop | `motion/duration/base` | 200 ms, linear, 100 ms dwell |

The Timing column is what each component animates with in the Figma file. The collection holds 31 variables, and every component that moves reads from it.

## Which components animate their own state change?

The library holds 9 Motion / sets that play their own transition on the Figma timeline. Search “Motion /” in the Assets panel and the instance animates as is. Each has one-shot variants and a Loop for presentations, all timed from the presets above.

The sets are Motion / Toggle, Checkbox, Radio, Button, Skeleton, Toast, Dialog, Sheet and Page Push. Place an instance in a top-level frame and press play. Use a one-shot variant in a prototype and Loop on a cover or in a presentation.

One-shot variants start at 0.2 s. Loop plays the change at 0.4 s and back at 1.4 s, so a 2 s timeline loops cleanly, and the drawings above play the Loop variants that way.

| Component | Variants | What moves | Timing |
| --- | --- | --- | --- |
| Toggle | Turn on, Turn off, Loop | The handle travels 16, Track on fades in | Handle `motion/toggle/state/spring`, subtle, 300 ms. Track 120 ms, standard |
| Checkbox | Check, Uncheck, Loop | The box scales in from 0.8 and the mark draws itself; Uncheck fades both | Box spring subtle, 300 ms. Fill and mark 120 ms, standard |
| Radio | Select, Deselect, Loop | The ring fills and the dot springs in from 0.4 | Dot spring subtle, 300 ms. Ring 120 ms, standard |
| Button | Tap, Loop | Scales to 96 percent and darkens on press, springs back on release | Press `motion/duration/fast` and `motion/easing/standard`, 120 ms. Release `motion/spring/subtle` |
| Toast | Enter, Exit, Loop | Enter drops 24 and fades in, Exit lifts 12 and fades out | Enter position spring subtle, opacity 120 ms decelerate. Exit 120 ms, accelerate |
| Dialog | Enter, Exit, Loop | The card scales in from 0.92 over a scrim, and out to 0.96 | Enter scale `motion/dialog/enter/spring`, default, 400 ms, opacity 200 ms emphasized. Exit 120 ms, accelerate |
| Sheet | Enter, Exit, Loop | The sheet rises 387 over a scrim | Enter sheet spring default, 400 ms, scrim 200 ms decelerate. Exit 120 ms, accelerate |
| Page Push | Push, Pop, Loop | The new screen slides in from the trailing edge, the old one shifts 30 percent and dims | `motion/page/push`, 200 ms, emphasized |
| Skeleton | One component | Three list rows pulse between 100 and 40 percent | `motion/skeleton/pulse`, 480 ms each way, linear, two cycles in 1.92 s |

Every chart except Legend animates on the same timeline. Bar raises each column 12 from a fade over 480 ms, 50 ms apart, and Line draws its current series over 600 ms on standard.

Eight example screens enter in reading order, in Light and Dark.

## What should motion do when Reduce Motion is on?

Swap the movement for a fade or an instant change and keep the state change. With Reduce Motion on, the Play buttons on this page move the dot to the end of the track without animating it.

A sheet still opens, a toggle still flips and a toast still appears. What goes is the travel: a slide, a scale or a spring becomes a fade at the same duration or a cut, so the new state is visible without the reader being moved across the screen.

Looping motion such as Skeleton pulse and Spinner stops on a still frame. The animated components above rest on their end state the same way, and their Pause button stops the loop at any time.
