Motion System: Uber Base Design System
Category: Transportation / Technology Fast, precise motion that inspires confidence — the interface should feel as reliable as the service.
Motion Philosophy
Uber's product operates at moments of real-world consequence. A rider is standing on a corner in an unfamiliar city. A driver is between trips, checking their next potential fare. These are not contemplative contexts — users need information fast, they need to trust what they see, and they need to act. Motion in the Uber product must serve those needs with precision. It is not there to delight or to entertain; it is there to communicate state changes with the clarity of a signal light.
The system is built around confidence as the emotional register. Transitions are fast and decisive — in the 150–250ms range for most UI interactions — and they use easing curves derived from ease-out-expo that give elements a crisp, authoritative arrival. There is no playfulness in the core product motion language: no bounce, no overshoot, no theatrical flourish. The product handles navigation, payments, and real-world coordination at scale; every motion decision reflects the seriousness of that task.
There is an important distinction in the Base system between driver and rider product motion registers. The rider app permits slightly more expressive motion — map animations, route reveals, driver location pulses — because the rider is in a passive, waiting state where engagement is appropriate. The driver app is more restrained: the driver is operating a vehicle and glancing at a screen. Motion here must be faster, more conservative, and never distracting. The Base system provides the same tokens and patterns to both but documents explicitly which patterns are appropriate for each surface.
Duration Scale
| Token | Value | Use |
|---|---|---|
| duration-instant | 0ms | Direct map manipulation, cursor-tracked elements, gesture-following |
| duration-fast | 150ms | Hover fills, button press feedback, icon state changes, badge updates |
| duration-default | 200ms | Dropdowns, tooltips, small panel transitions, bottom sheet peek |
| duration-move | 250ms | Modals, full-panel transitions, tab changes |
| duration-slow | 400ms | Map-level transitions, route reveals, onboarding flows |
| duration-expressive | 600ms | Pin drop animation, driver arrival confirmation, trip start sequence |
Easing
| Token | Curve | Use |
|---|---|---|
| ease-productive | cubic-bezier(0.16, 1, 0.3, 1) | Primary UI ease — fast start, smooth precise deceleration |
| ease-out | cubic-bezier(0.0, 0.0, 0.2, 1) | Standard element entry |
| ease-in | cubic-bezier(0.4, 0.0, 1.0, 1.0) | Standard element exit |
| ease-map | cubic-bezier(0.25, 0.46, 0.45, 0.94) | Map camera moves, route reveals — softer for spatial transitions |
| ease-linear | cubic-bezier(0, 0, 1, 1) | Loading bars, progress indicators, pulsing location rings |
ease-productiveis the signature Uber curve. The aggressive initial acceleration (control point at x=0.16) gives transitions a snap that communicates decisiveness and speed — matching the brand promise. This curve at 200ms feels faster than Material's ease-out at the same duration.
Spring Configs (Framer Motion)
Springs are used only for map and location interactions in the core product. General UI chrome uses CSS transitions with ease-productive.
- Pin drop (location selection on map): stiffness: 380, damping: 28, mass: 0.7 — visible overshoot and bounce, communicates the pin "landing" on the map
- Map camera snap (re-centering on driver location): stiffness: 200, damping: 28, mass: 1 — gentle, no overshoot; the camera is always moving somewhere purposeful
- Bottom sheet (pickup address sheet, trip options): stiffness: 300, damping: 35, mass: 1 — slight overshoot on open, snaps cleanly
- Driver card arrive (driver info panel enters): stiffness: 320, damping: 30, mass: 0.9 — slight bounce to signal the moment of confirmation
No springs in the driver app. The driver-facing components exclusively use CSS transitions with ease-productive for predictability.
Stagger Patterns
- Trip options (UberX, Comfort, etc.): 30ms between each option card on initial load, entering from bottom
- Recent places in address search: 20ms between each item
- Receipt line items: 16ms between each line item when the receipt first renders
- Surge pricing zones on map: appear simultaneously — zone boundaries are drawn, not staggered
- Notification list: 25ms between each item
Stagger is applied only on initial mount. Real-time updates (driver location, ETA changes) never use stagger.
Enter / Exit Patterns
Fade + Slide (tooltips, popovers, small menus)
enter: opacity 0→1, translateY 6px→0, duration: duration-default (200ms), ease: ease-productive
exit: opacity 1→0, duration: duration-fast (150ms), ease: ease-in
Bottom Sheet (primary product pattern — address input, trip options, driver info)
enter: translateY 100%→0, spring: Bottom sheet config
exit: translateY 0→100%, duration: duration-move (250ms), ease: ease-in
drag dismiss: follows finger, spring snap back if below threshold, spring dismiss if above
Full-screen overlay (surge map, promo screens)
enter: opacity 0→1, scale 0.98→1, duration: duration-move (250ms), ease: ease-productive
exit: opacity 1→0, duration: duration-fast (150ms), ease: ease-in
Map Route Reveal (route line drawing on map)
stroke-dashoffset animates from full path length → 0, duration: duration-slow (400ms), ease: ease-map
Route line draws from origin toward destination. Simultaneously, camera fits route bounds with spring: Map camera config.
Pin Drop
enter: scale 0→1.3→1.0, spring: Pin drop config. Drop shadow appears at 0ms. Pin bounces once and settles.
confirm (pin tapped): brief scale pulse 1→1.1→1, duration: 200ms, spring: Pin drop at higher stiffness (500)
Trip Status Transition (request → matching → confirmed)
Status pill: crossfade between text states, duration: duration-fast (150ms), ease: ease-productive
Map reconfigures: camera, route, and pin all animate simultaneously using their respective configs
Driver card: enters via Spring Driver card config from bottom
Interaction States
- Hover (web): Background fill at duration-fast (150ms) ease-productive. No scale on primary action buttons. Icon-only controls get a circular background fill at 150ms.
- Press/Active: Scale 1→0.97 on primary buttons at duration-fast (150ms) ease-productive, returning to 1.0 at release. On mobile, haptic feedback pairs with press confirmation. Background color darkens by 8% at 0ms.
- Focus: Focus ring at 2px, brand black
#000000, appears at duration-fast (150ms). In reduced-motion or driver contexts, 0ms. - Loading (matching state): Pulsing rings radiating from driver pin on map — opacity 0.6→0 over 1200ms linear, looping, 3 rings staggered 400ms apart. Skeleton sheets use gradient shimmer at 1600ms linear infinite.
- ETA update: Number ticks up or down with a brief translateY transition — old number exits translateY 0→-8px at 100ms ease-in, new number enters translateY 8px→0 at 150ms ease-productive. No opacity change — the motion alone signals the update.
- Driver location pulse: Circular pulse ring on driver icon, 1400ms linear, infinite, opacity 1→0, scale 1→2.5.
- Reduced motion: All transforms removed. Opacity fades at 100ms maximum. Pin drop becomes instant scale-in. Map route draws instantly. Bottom sheet snaps in without spring. Driver location pulse stops.
Rules
- Speed signals confidence. Durations above 300ms are reserved for map-level and trip-confirmation moments. General UI transitions at 200–250ms and hover states at 150ms ensure the interface feels as fast as the service.
- Springs are for the map, not the chrome. Pin drops, route reveals, and driver location animations benefit from physics because they are representing real-world, physical events. UI chrome — buttons, drawers, menus — uses deterministic CSS transitions.
- The driver app is a safety-critical surface. Never use expressive springs, bounce, or stagger in driver-facing components. All driver UI motion uses
ease-productiveCSS transitions at duration-fast (150ms) or duration-default (200ms) maximum. - Always implement
prefers-reduced-motion. When active, all transforms are disabled, springs snap to end state, map animations are instant, and pulsing location rings stop. The full product must be usable without any motion.