Irozon Design System — design foundations, tokens and components by Irozon AB.
Irozon Design System · v1.0
Motion & Interaction Foundations v1

Quiet at rest. Precise and alive during interaction.

We admire Apple's attention to micro-interaction, timing and physical feedback — this page borrows that craft, not Apple's visual identity or animation style. Irozon motion is premium, restrained, responsive and technically polished. It is never decorative for its own sake: no flashy reveals, no excessive springs or bouncing, no glow, no large transforms, no animation just because an element can move.

Motion exists to communicate something: a state change, hierarchy, cause and effect, continuity, feedback on input, or a spatial relationship. If a transition doesn't communicate one of those, the interface is better off without it.

Immediate feedback

Interactive controls acknowledge input quickly — feedback lives on press, not on release. A control that waits to respond feels disconnected from the hand that touched it.

Continuity

Elements entering or leaving preserve spatial understanding. Something that opens from a trigger should feel anchored to it; something that closes should retreat along a path the eye can follow, not vanish and reappear elsewhere.

Restraint

Small interactions deserve small movement. A hover color shift doesn't need a scale change; a scale change doesn't need a shadow escalation on top of it. Add exactly one signal, not three.

Hierarchy

The larger or more consequential the change, the more deliberate the transition may be. A button's hover is instant; a drawer taking over part of the screen earns a slower, more considered entrance.

Consistency

The same interaction type feels the same everywhere in an Irozon product. One hover treatment for cards, one press feedback for buttons, one popover behavior — not a different feel per screen because a different person built it.

Timing & easing

Two small scales cover almost everything.

Four durations, four easings. Reach for a fifth value only when a real interaction genuinely can't be served by these — don't let one-off timings creep back in. Every transition below animates named properties explicitly (transform, opacity, background…); Irozon interactions never reach for transition: all as a default, since it silently animates properties that were never meant to move and makes performance and intent both harder to reason about.

Duration

Hover a card (or Tab to it) to preview its timing.

Instant
100ms
--motion-duration-instant — press/active feedback, a toggle's flip.
Fast
150ms
--motion-duration-fast — hover state changes, a small icon nudge.
Standard
220ms
--motion-duration-standard — dropdowns, tabs, popovers, selection.
Deliberate
400ms
--motion-duration-deliberate — drawers, modals, larger panels.

Easing

All four run at the same duration here so only the curve shape differs. Replay to compare them side by side.

Standard cubic-bezier(.4, 0, .2, 1)
Enter cubic-bezier(0, 0, .2, 1)
Exit cubic-bezier(.4, 0, 1, 1)
Emphasized cubic-bezier(.2, 0, 0, 1)

How to choose

  • Standard — the default when nothing more specific applies: symmetric, unremarkable, correct almost everywhere.
  • Enter — fast out of the gate, settles gently. Use whenever something appears (a popover opening, a panel revealing).
  • Exit — starts unhurried, then leaves quickly. Use whenever something is dismissed — departure should read as faster than arrival, not a mirror image of it.
  • Emphasized — a longer, more pronounced deceleration, reserved for the deliberate tier's largest spatial movement (a drawer or modal). Still no overshoot.

One exception exists outside this scale: a single, deliberately springy easing reserved for the Signature CTA's reveal (see Buttons) and not reused anywhere else. Every other interactive default on this page is critically damped — it settles into place without overshoot or oscillation. A system built on springs everywhere stops feeling premium and starts feeling busy; reserve bounce for the one interaction it was tuned for.

Live demonstrations

Interact with it, not just read about it.

Every example below is real CSS/JS running on this page, not a video or a description. Try them with a mouse, a touchscreen and a keyboard.

Hover

A navigation link, a button and an interactive card — each gets exactly one signal, never elevation or movement just because an element can respond.

Navigation link Color + underline reveal
Background + border tint
Border color only

Press / tap

A tiny, single-property scale — never enough to feel unstable. Feedback fires on press (:active), not on release.

scale(0.97), instant
Same recipe, secondary weight

Focus

Focus is an accessibility state, not decoration — the outline appears the instant a control receives keyboard focus, with no delay and no fade to obscure it. Press Tab to move through these three controls.

Selection

A single indicator layer slides to the selected option, rather than each button independently swapping its own background — the eye tracks one moving shape.

Enter & exit

A popover anchored to its trigger. Entry settles in gently over the standard duration; exit is quicker and more direct — dismissal shouldn't linger. Try opening it, then close it with Esc, an outside click, or the trigger itself.

Drawer / modal

The largest spatial movement in the system: the deliberate duration, emphasized easing, and a dimming backdrop that separates the panel from the page behind it. Bounded to this stage rather than the real viewport — the real navigation drawer elsewhere on this site uses this same recipe. Esc, the close control, or the backdrop all dismiss it.

Cards

Only a card that's genuinely interactive (it navigates, opens, or selects something) responds on hover. A card that merely displays information stays completely still — motion here is a promise about what happens if you click, not a decoration.

Border tints

Static

Displays information only — stays still.

No response, and none needed

Status / state change

A label and its indicator dot cross-fade between states. The change draws the eye through color and text, never through a bounce, a scale-up, or a celebratory flourish.

Pending

Loading / progress

A spinner is reserved for a button carrying out a committed action — brief, and on the control the user just pressed. Content that's still arriving uses a skeleton surface instead of a spinner; the shape of what's coming communicates progress better than a generic loading icon.

Button loading state

Project loaded

Real content, same footprint as the placeholder it replaced.

Icon state change

Copy → Check: the confirmation this recipe is built from. Both icons occupy the exact same centered cell — no layout shift, no rotation, no bounce — and crossfade with a very small scale change at instant speed. The check remains briefly, then reverts on its own.

Opacity + scale, ~100ms, no rotation
Interaction recipes

Duration and easing, by interaction.

A compact reference, not an exhaustive rulebook — most Irozon products only ever need this table.

Interaction Duration Easing
Button / link hoverfast · 150msstandard
Button / control pressinstant · 100msstandard
Navigation hoverfast · 150msstandard
Card hover (border only)fast · 150msstandard
Selection indicator movestandard · 220msstandard
Popover / menu enterstandard · 220msenter
Popover / menu exitfast · 150msexit
Drawer / modal opendeliberate · 400msemphasized
Drawer / modal closedeliberate · 400msexit
Status / state changestandard · 220msstandard
Skeleton → content swapstandard / fastenter / exit
Icon state change (Copy → Check)instant · 100msstandard
Component interaction guidance

Per-component recipes, not one universal hover.

There is no rule that every component tints green, lifts, or gains a shadow on hover. Each component gets exactly the signal it needs — often less than you'd expect.

Interactive row / interactive surface

A large clickable row (a list item, a table row) stays quiet at rest — no heavy selected-looking fill, no automatic shadow or lift on hover. If the row already has a trailing affordance (a chevron, an external-link glyph), emphasize that instead of tinting the whole row. Where a subtle surface hover genuinely helps, keep it as a semantic recipe rather than a repeated arbitrary utility value — roughly primary-surface ~4–5% / primary-border ~10%. :focus-visible stays independent of hover, and touch never inherits a sticky mouse-hover state.

Icon button

The canonical square icon-only button — fixed geometry, centered icon, keyboard accessible, with hover/focus/disabled/press and reduced-motion owned entirely by the primitive. See Buttons for the data-icon-only API and its aria-label requirement.

Trailing action indicator

Not the same thing as an icon button. A trailing action indicator (Copy → Check, a chevron, an external-link glyph) is a non-interactive affordance inside a row or control that is already the interaction target — it never gets its own focus stop or click handler. An IconButton is an independently interactive control in its own right. Nesting one inside the other's hit area creates a confusing double target; pick one role per element.

Interaction states

Seven states, not interchangeable.

A control can be in more than one of these at once — but each communicates something the others don't.

StateCommunicatesRule
RestThe default, quiet stateNothing moves when nobody is interacting.
Hover"This responds to input"Never the only indication of interactivity — pointer-only, absent on touch.
Focus"Keyboard interaction is here"Always visible independently of hover; never delayed or obscured.
Active / pressed"Input is landing right now"Transient — fires on press, releases on release, never persists.
Selected"This is the current choice"Persists after the pointer leaves — a fundamentally different signal from hover.
Disabled"Not available right now"Never animates as if active — no hover, no press feedback, no transitions.
Loading"In progress"Replaces the active affordance; the control that triggered it stays visibly busy, not silent.
Reduced motion

prefers-reduced-motion: reduce is not "no motion."

Reduced motion does not mean removing every state change — it means removing travel. Interactive controls, status, selection and loading must all remain just as clear; only the spatial journey between states goes away.

  • Eliminate translation and scale — an element still changes, it just no longer moves to get there.
  • Shorten or remove spatial animation on drawers, panels and popovers; a quick cross-fade replaces the slide.
  • Preserve immediate visual feedback — hover, press and background/color changes stay, since they don't rely on spatial travel.
  • Keep focus, selection, loading and status changes exactly as legible as with motion on.
  • An open-ended, looping animation (a marquee, an infinite spinner) needs its own explicit guard — a loop has no natural "end state" to just skip to.

Every transition on this page — including every demonstration above — is wrapped in a @media (prefers-reduced-motion: reduce) rule (and mirrored here via a .force-reduced-motion class) that removes transform/scale/opacity travel and lets the state change land instantly instead. Toggle this on, then scroll back up and try the drawer, the popover or the segmented control again.