Foundations
Motion
Transition timing tokens, easing functions, and the rules that keep animation purposeful rather than distracting.
Motion in a travel product carries weight. A traveller comparing holidays is making a significant decision; distracting animation erodes trust. The Kuoni approach is purposeful restraint: transitions communicate state change (hover lift, menu open, modal appear), never decorate for decoration's sake.
Three transition tokens cover every situation. They are the only values that
should appear in transition-* CSS properties across the system.
Transition tokens
transition.fast
120ms easeMicro-interactions — hover colour changes, focus ring appearance, icon state flips, toggle thumb movement
transition.normal
200ms easeComponent-level transitions — shadow lift on card hover, dropdown open/close, accordion expand, sidebar collapse
transition.slow
300ms ease-in-outLarge surface transitions — Modal open/close, Drawer slide, full-page route changes, image fade-in on load
Token reference
| Token | Value | Tailwind | When to use |
|---|---|---|---|
transition.fast | 120ms ease | duration-[120ms] ease-in | Colour, opacity, border-colour, text-colour changes on hover/focus |
transition.normal | 200ms ease | duration-200 ease-in-out | Shadow lift, width/height, visibility, position within a component |
transition.slow | 300ms ease-in-out | duration-300 ease-in-out | Overlay appear/disappear, page-level enter/exit, large layout shifts |
The ease function (fast/normal) accelerates out of the resting state smoothly.
ease-in-out (slow) is symmetric — used for reversible transitions that must
feel equally natural in both directions (modal open and modal close).
What to animate
Animate these properties
box-shadow— card hover lift fromshadow-kuoni-smtoshadow-kuoni-mdbackground-color/color— hover state on buttons, links and nav itemsborder-color— focus ring appearance on inputs and interactive controlsopacity— overlay backdrops, tooltip/popover fade-intransform: translateY— Drawer slide up/down, Modal slight upward entermax-height/height— accordion expand/collapse
Use Tailwind transition utilities
{/* Card hover lift — transition.normal */}
<div className="rounded-md bg-white shadow-kuoni-sm transition-shadow duration-200 hover:shadow-kuoni-md">
...
</div>
{/* Button colour change — transition.fast */}
<button className="bg-kuoni-yellow transition-colors duration-[120ms] hover:bg-kuoni-yellow500">
...
</button>
What NOT to animate
Animate shadow and background-color on interactive cards.
Shadow and colour transitions give clear hover feedback without moving content.
Animate transform: scale(1.05) on a TripCard or DestinationCard.
Moving card content on hover is disorienting and interferes with reading.
Animate a Modal entrance with a 300ms opacity + slight translateY.
300ms is the right budget for an overlay; it feels deliberate but not slow.
Apply transition.slow to micro-interactions like checkbox toggle or button press.
Slow transitions on small UI — a checkbox taking 300ms to check — feel broken.
Never animate these
- Layout shifts (width/height of content containers that cause reflow)
- Font size or font weight (causes text reflow and looks broken)
- Z-index (stacking order cannot be interpolated meaningfully)
- Content that has already loaded — images, text, prices must not fade in after mount in production; this hides content from users on slow connections
Reduced motion
Always respect the prefers-reduced-motion media query. Users who have
requested reduced motion in their operating system — often people with
vestibular disorders — should see no transitional animation.
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
This rule is already in the global stylesheet. Do not write animation code that works around it. If a state change is purely informational (a filter chip selecting, a toggle switching), the end state is sufficient — the transition is enhancement, not communication.
Animation in components
The table below lists every component that uses motion and its timing.
| Component | Property animated | Token |
|---|---|---|
Card, TripCard, DestinationCard | box-shadow on hover | normal |
Button | background-color on hover | fast |
Toggle | thumb translateX, track background-color | fast |
Modal | opacity + translateY on open/close | slow |
Drawer | translateX on open/close | slow |
Sidebar section | max-height on accordion open | normal |
ChevronDown in dropdowns | rotate 0° → 180° | normal |
Popover | opacity on appear | fast |
Banner | translateY on dismissal | normal |
ProgressBar | width on value change | slow |