Transitions & transforms
Use the rotate-*, scale-*, and transition-* utilities to add motion to elements. They’re commonly combined: a transition-transform class is what makes a rotate-* or scale-* animate smoothly between states instead of snapping.
Transitions use the design system’s transition speed tokens. Durations automatically shorten when a user has prefers-reduced-motion enabled.
Rotate
Section titled “Rotate”Rotate an element using a CSS rotate transform.
| Class | Rotation |
|---|---|
rotate-0 | 0deg |
rotate-90 | 90deg |
rotate-180 | 180deg |
-rotate-90 | -90deg |
<img src="arrow-16.svg" alt="" class="icon-sprite rotate-90" width="16" height="16"/>State-driven rotation
Section titled “State-driven rotation”The most common use is rotating a chevron when an ancestor button or <details> is opened, using the button-expanded: or details-open: modifiers with rotate-180. Pair with transition-transform so the rotation animates.
<button type="button" aria-expanded="false"> <img src="https://www.volvocars.com/static/shared/icons/v5/chevron-down-16.svg" alt="" class="icon-sprite transition-transform button-expanded:rotate-180" width="16" height="16" /></button>
<details> <summary> <img src="https://www.volvocars.com/static/shared/icons/v5/chevron-down-16.svg" alt="" class="icon-sprite transition-transform details-open:rotate-180" width="16" height="16" /> Show details </summary> …</details>In React, the same markup is produced by <Icon icon="chevron-down" /> from @volvo-cars/react-icons: apply the rotation and transition classes via its className prop.
Show code
<details class="bg-secondary p-16"> <summary class="flex items-center gap-8"> <img class="icon-sprite transition-transform details-open:rotate-180" width="16" height="16" src="https://www.volvocars.com/static/shared/icons/v5/chevron-down-16.svg" alt="" /> Show details </summary> <p class="mt-16"> The chevron rotates 180° when the details element is open. </p></details>Scale an element using a CSS scale transform. The named values map to the design system’s interaction scales.
| Class | Scale | Typical use |
|---|---|---|
scale-96 | 0.96 | Same as scale-pressed |
scale-100 | 1 | Reset to the default size |
scale-110 | 1.1 | Same as scale-zoomed |
scale-pressed | 0.96 | Pressed/active feedback |
scale-zoomed | 1.1 | Hover zoom for media and tap areas |
State-driven scaling
Section titled “State-driven scaling”A common pattern is zooming on hover and shrinking on press, either on the element itself (hover:, active:) or on a descendant of a hovered ancestor (button-hover:, link-hover:). See interaction states for how each modifier resolves.
<button type="button" class="transition-transform hover:scale-zoomed active:scale-pressed"> Press me</button>
<a href="/cars" class="block overflow-hidden"> <img src="car.avif" alt="" class="transition-transform link-hover:scale-zoomed" /></a>Without transition-transform the size change is instant. Pair scale utilities with a transition unless you want the snap.
Transition
Section titled “Transition”Control which properties animate when an element’s state changes. Pick the narrowest transition that covers what you’re animating. Avoid transitioning everything.
| Class | Animates |
|---|---|
transition-colors | color, background-color, border-color, box-shadow, fill, stroke, text-decoration-color |
transition-opacity | opacity |
transition-transform | transform, scale, rotate, translate, skew |
transition-none | Disables transitions |
All transitions use the default design system speed token, which automatically respects prefers-reduced-motion.
<button type="button" class="border-2 border-tertiary transition-colors hover:border-primary"> Hover me</button>Show code
<div class="flex gap-16"> <button type="button" class="border-2 border-tertiary p-16 transition-colors hover:border-primary" > With transition-colors </button> <button type="button" class="border-2 border-tertiary p-16 hover:border-primary" > Without transition </button></div>When to combine
Section titled “When to combine”- Use
transition-transformwithrotate-*orscale-*so state-driven rotation and scaling animate smoothly. - Use
transition-colorsfor hover/selected/checked styles that changeborder-*,bg-*, or iconfill/stroke. - Use
transition-opacitywhen toggling visibility via opacity, for example fading a tooltip or overlay in and out.
Animation
Section titled “Animation”Use the fade-in utility class to fade an element in using the design system’s default animation curve, without writing custom keyframes.
<img src="/images/decorative/ex60-road.avif" alt="" class="img fade-in" width="1200" height="675"/>Show code
<img class="img fade-in" src="/images/decorative/ex60-road.avif" width="1200" height="675" alt=""/>fade-in animates opacity from 0 to 1 using the --v-transition-notable duration and easing, so it automatically respects prefers-reduced-motion.
Tokens
Section titled “Tokens”The transition utilities above are built on three transition timing tokens (duration + easing). Use them directly in custom CSS when the utility classes don’t cover your needs.
| Custom property | Value | Use case |
|---|---|---|
--v-transition-default | 220ms ease | The default choice for most transitions |
--v-transition-micro | 110ms ease | Fast, subtle feedback, such as press states |
--v-transition-notable | 800ms ease | Slower, noticeable motion, such as fading in/out |
All three automatically shorten when a user has prefers-reduced-motion enabled.