Blog · October 18, 2026

How long should a UI animation actually take?

When an interface feels sluggish, the easing curve usually gets the blame. Most of the time the real problem is the clock: the animation simply runs too long. The useful numbers have been published for years, and they are shorter than most people guess. Here is where they come from and how to pick one for each kind of motion.

Two clocks, not one

Every animation has two timings, and they follow different rules. The first is how quickly the response starts. The second is how long the motion lasts.

The start time is the strict one. Jakob Nielsen’s response-time limits, drawn from Robert Miller’s 1968 research, put the threshold for “instant” at 0.1 seconds. Under that, the result feels caused by the user’s own action. Over it, people start to feel the computer doing something on their behalf. For a button press that 100 ms is a ceiling, not a target. A press should show a visible change on the next frame, which is 16.7 ms at 60 Hz and 8.3 ms on a 120 Hz screen. Flutter’s Material ink ripple fades in over 75 ms, but its first frame is visible right away, and that first frame is what makes the tap feel connected.

Duration is the looser clock. A press can respond in one frame and still run its full animation over 200 ms, and that feels good. What feels bad is a button that does nothing for 150 ms while a fancy transition gets ready.

The ranges the platforms publish

The original Material Design motion guidance is still the clearest written reference. It says mobile transitions typically run around 300 ms. Elements entering the screen take 225 ms, elements leaving take 195 ms, and large full-screen transitions can stretch to 375 ms. It also warns that “transitions that exceed 400ms may feel too slow.” Desktop gets 150–200 ms because pointer users move faster and the distances are smaller relative to what they can see. Tablets get roughly 30% longer than phones (300 ms becomes 390 ms) and wearables roughly 30% shorter (210 ms).

Material 3 swapped those rules of thumb for a token scale, and Flutter ships it as the Durations class: sixteen steps from short1 at 50 ms to extralong4 at 1,000 ms, in 50 ms and then 100 ms increments. A scale is not advice, though. Having a 1,000 ms token does not mean anything in your app should take a second.

The framework defaults are revealing. Flutter’s theme changes animate over 200 ms (kThemeAnimationDuration). The iOS-style page push is 500 ms. The newer Android page transition is 450 ms, and the source comment says that value was “eyeballed on a physical Pixel 9.” It also notes that native Android takes 800 ms using springs Flutter can’t yet reproduce. Page transitions run longer than component motion because the whole screen changes, and because a spring’s long, slow tail doesn’t feel like waiting. Most of the visible movement is over well before the numbers settle.

Let size and distance set the number

The most useful rule in that old guidance is the one people skip: duration should scale with how far something travels and how much its surface changes. A checkbox tick moving 12 points needs far less time than a sheet rising across the whole screen. Give both 300 ms and the checkbox will feel lazy while the sheet feels rushed.

These are the working ranges we use. They are a starting point drawn from the guidance above, not a standard:

motion                        range
press / toggle / checkbox     80–150 ms
tooltip, menu, small fade     120–200 ms
card expand, dialog in        200–300 ms
sheet, full-screen push       300–500 ms

If something sits outside its row, it should be for a reason you could explain. “It looked smoother in the design tool” isn’t one. Prototypes play once, on a big monitor, to someone watching for the motion. Your users see it for the fortieth time that day, on their way to something else.

Exits are faster than entrances

Material’s 225 ms in and 195 ms out is a small gap with a big reason behind it. An element arriving needs attention, because the user has to see what it is and where it came from. An element leaving needs none, because the user already decided they were done with it. Making a closing dialog take as long as an opening one makes people wait to get back to what they wanted. A rough rule is exits at 70–85% of the entrance. In Flutter that means setting reverseDuration on the AnimationController or reverseTransitionDuration on a route, instead of letting the reverse reuse the forward duration.

Frequency shortens everything

The more often an animation plays, the shorter it should be. Once a motion has done its job of showing where something came from, every repeat is pure delay. A paywall reveal shown once can take its time. A tab switch made 200 times a week should be quick, or have no motion at all. Look at the tab bars in Apple’s own apps: switching tabs is close to instant, while pushing into a detail view slides. That split matches what each one has to explain.

Springs change the question

Apple moved its frameworks toward springs, and since WWDC23 a spring is described by just two values: a duration and a bounce, as in .spring(duration: 0.6, bounce: 0.2) in SwiftUI. Apple calls that duration a perceptual duration. It sets the pace and roughly matches the settling time, but a bouncy spring keeps moving slightly past it. Apple’s advice is not to wait for the settling time before letting the user continue.

That advice applies to any animation system. Whatever the duration, the animation must never block input. If someone taps again halfway through, the motion should turn from where it is toward the new target, not finish the old journey first. Springs do this naturally because they carry velocity. With a Flutter AnimationController, calling animateTo or reverse mid-flight starts from the current value, so the work is mostly not disabling taps while it plays. An interruptible 350 ms animation feels faster than an uninterruptible 250 ms one.

How to check the numbers

Watch your motion at a slower speed. The iOS Simulator has Slow Animations in its Debug menu, Android’s developer options have an Animator duration scale, and Flutter exposes timeDilation in package:flutter/scheduler.dart. At 5× slower you can see whether things move in the order you meant, whether exits clear before entrances land, and whether two elements fight over the same moment.

Then judge the timing at full speed, using the app the way users do. Make the same action ten times quickly. If you notice yourself waiting, the duration is too long. If you can’t tell where something came from, it’s too short or travelling too far. We did a quick count of the duration literals in our own Flutter app, and the most common were 200, 150 and 180 ms. That’s roughly where this process ends up for component motion.

Reduced motion is part of the timing: when the user turns on Reduce Motion (iOS), Remove animations (Android), or prefers-reduced-motion (web), don’t just shorten the slide. Swap travel for a short crossfade of around 150 ms, so state changes are still visible but nothing moves across the screen. Flutter reports the setting through MediaQuery.disableAnimationsOf(context).

The short version: start the response within a frame, keep most motion between 150 and 300 ms, scale it up only for distance, cut it for exits and repeats, and never make anyone wait for it to finish. App Store preview videos have their own pacing rules, which we cover in our preview video guide.

Design your store screenshots → Making a 10-second AI wait feel fast