Shopware Design

Motion

Enter: 250ms decelerate. Exit: 150ms accelerate.
Movement: 300ms standard.
Draft
Color: 150ms ease.

Merchants spend entire workdays in the admin completing business-critical tasks. Motion in this context is feedback, not decoration. It confirms that a click registered, shows where an element came from, and keeps state changes from feeling abrupt. Users should notice what changed, never the animation itself.

When in doubt, do not animate. A fast, well-eased 150ms transition beats an elaborate 500ms sequence every time.

Principles

  • Minimal. Use only as much motion as necessary. Every movement has a clear purpose, so users can focus on their work rather than the interface.
  • Purposeful. Every animation answers a question: did my click register, where did this element come from, what just changed. If it answers no question, cut it.
  • Calm. Motion in Meteor is professional and quiet. Avoid playful, bouncy, or hectic movement. Save expressiveness for rare moments such as onboarding or empty states, never for everyday interactions.

Marketing surfaces follow their own motion guidelines with longer, more expressive timing. Those values are designed for storytelling and do not transfer to product interfaces.

When to animate

Decide based on how often a user triggers the change:

FrequencyExampleMotion
Many times per hourNavigating lists, moving selection, toggling table rowsNone, or 100ms at most
Keyboard-initiatedFocus movement, arrow-key navigation, shortcutsNever animate
OccasionalOpening a modal, popover, or drawerStandard, under 400ms
RareOnboarding, empty states, success momentsMay be slightly more expressive

High-frequency actions must feel instant. Animating them makes the interface feel disconnected from the user's input, and the delay compounds hundreds of times a day. Click through both lists quickly, or hold an arrow key, to feel the difference:

Instant: keeps up with held arrow keys.
Animated 250ms: lags behind rapid input.

Duration

ElementDuration
Hover, press, color, and shadow changes100-150ms
Tooltips, dropdowns, popovers150-250ms
Modals, drawers, side panels250-400ms
  • Exits run 30-50% faster than entrances. The user has already decided to leave; do not make them wait. Modal enters in 400ms and exits in 200ms.
  • Larger elements and longer travel distances get more time. A full-height drawer needs more than a tooltip.
  • 400ms is the ceiling for any product UI animation. If motion feels slow, reduce the duration before changing anything else.

The same enter and exit transition at three durations:

100msMicro feedback
250msStandard transition
600msToo slow for product UI

Easing

Three curves cover Meteor interfaces:

RoleCurveUse for
Deceleratecubic-bezier(0.05, 0.7, 0.1, 1)Elements entering the screen
Acceleratecubic-bezier(0.3, 0, 0.8, 0.15)Elements leaving the screen
Standardcubic-bezier(0.4, 0, 0.2, 1)Movement and resizing of elements already on screen
Decelerate
cubic-bezier(0.05, 0.7, 0.1, 1)
Standard
cubic-bezier(0.4, 0, 0.2, 1)
Accelerate
cubic-bezier(0.3, 0, 0.8, 0.15)
Linear
linear

Entrances decelerate: they start fast, so the interface reads as responding instantly, then land softly. Exits accelerate: they get out of the way without ceremony. The built-in ease keyword is acceptable for hover and color changes.

Reserve linear for constant motion such as the Loader spinner or a Progress Bar. Everywhere else it feels rigid and mechanical. Never use a pure ease-in curve for an entrance; it delays feedback at the exact moment the user is watching most closely.

Entering and exiting

Elements never appear from nothing or grow from a point. Pair a quick fade with a subtle scale from 0.9, so the element always has a visible shape:

The canonical pattern for a Vue transition, including the reduced motion fallback:

.panel-enter-active {
  transition: opacity 250ms cubic-bezier(0.05, 0.7, 0.1, 1);

  @media (prefers-reduced-motion: no-preference) {
    transition:
      opacity 250ms cubic-bezier(0.05, 0.7, 0.1, 1),
      scale 250ms cubic-bezier(0.05, 0.7, 0.1, 1);
  }
}

.panel-leave-active {
  transition: opacity 150ms cubic-bezier(0.3, 0, 0.8, 0.15);

  @media (prefers-reduced-motion: no-preference) {
    transition:
      opacity 150ms cubic-bezier(0.3, 0, 0.8, 0.15),
      scale 150ms cubic-bezier(0.3, 0, 0.8, 0.15);
  }
}

.panel-enter-from,
.panel-leave-to {
  opacity: 0;

  @media (prefers-reduced-motion: no-preference) {
    scale: 0.9;
  }
}
  • Elements that move as a unit share timing. A modal and its backdrop, or a popover and its arrow, use identical duration and easing. Mismatched timing reads as broken.
  • Anchored elements such as a Popover or Tooltip scale from their trigger via transform-origin, not from the center. Modals are the exception and stay centered.
  • Exits are quieter than entrances: a fade with a small scale or nudge, not a dramatic slide across the screen.

Implementation

  • Animate only transform (including translate and scale) and opacity. These run on the GPU and skip layout work. Never animate width, height, margin, padding, or top/left.
  • Use CSS transitions for anything the user can toggle. Transitions retarget smoothly when interrupted mid-animation; keyframes restart from zero and look broken. Reserve @keyframes for loaders and one-shot sequences that always run to completion.
  • Name transition properties explicitly. transition: all picks up properties you never intended to animate and breaks silently when styles change.
  • Do not animate elements into place on initial page load. Save motion for state changes the user causes.
Do
  • Animate transform and opacity with an explicit property list.
  • Use the decelerate curve for entrances and the accelerate curve for exits.
  • Keep every product UI animation at 400ms or less, with exits faster than entrances.
  • Give paired elements, like a modal and its backdrop, identical duration and easing.
Don't
  • Write transition: all or inherit timing from a copied snippet.
  • Animate width, height, margin, or top/left.
  • Animate keyboard-initiated changes such as focus movement.
  • Enter from scale(0) or slide in from outside the viewport.

Accessibility

Respect prefers-reduced-motion in every animation you ship. Reduced motion means removing movement, not removing feedback: drop scale, translate, and other positional changes, and keep quick opacity or color fades that aid comprehension. The pattern in the code sample above gates all movement behind prefers-reduced-motion: no-preference, which is the standard used across Meteor components.

Motion must never delay information. Move focus and trigger screen reader announcements when the state change starts, not after the animation finishes. Errors, confirmations, and focus indicators appear immediately.

Avoid flashing, rapid oscillation, and large sweeping movements across the viewport. They can cause discomfort and motion sickness regardless of the user's system settings.