Design Tokens

Duration

Create and manage duration design tokens with CSS variables for consistent animation and transition timing across your application.

Overview

The duration composables help you create consistent animation and transition timing systems with minimal code. They generate duration variables that can be easily referenced throughout your application, enabling flexible theming and consistent motion design.

Why use duration composables?

Duration composables help you:

  • Centralize timing values: Define all your animation durations in one place for easy management.
  • Enable flexible theming: Override duration values to instantly update animation speed across your application.
  • Maintain consistency: Use semantic names to ensure consistent timing throughout your design system.
  • Eliminate magic numbers: Replace hardcoded millisecond values with meaningful token names.

useDuration

The useDuration() function creates a set of duration variables from a simple object of timing value definitions. It includes sensible defaults covering a full range from instant (0ms) through slowest (1000ms).

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useDuration } from '@styleframe/theme';

const s = styleframe();

const {
    duration,
    durationFast,
    durationNormal,
    durationSlow,
} = useDuration(s, {
    default: '@normal',
    fast: '150ms',
    normal: '250ms',
    slow: '300ms',
} as const);

export default s;

Each key in the object becomes a duration variable with the prefix duration, and the export name is automatically converted to camelCase (e.g., defaultduration, fastdurationFast).

Pro tip: Use the default key for your primary duration. It will create a variable named --duration without any suffix, making it the natural choice for standard transitions throughout your application.

Default Values

The useDuration() composable comes with comprehensive defaults. You can use them directly without passing any arguments:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useDuration } from '@styleframe/theme';

const s = styleframe();

// Use all defaults
const {
    durationInstant,
    durationFastest,
    durationFaster,
    durationFast,
    durationNormal,
    durationSlow,
    durationSlower,
    durationSlowest,
} = useDuration(s);

export default s;

Duration Scale

NameValueUse Case
instant0msImmediate state changes, no animation
fastest50msMicro-interactions (ripple effects)
faster100msHover and focus states
fast150msButton presses, toggles
normal250msStandard UI transitions (modals, dropdowns)
slow300msPage transitions, complex reveals
slower500msSpring and bounce animations
slowest1000msFull-page animations, onboarding flows

Using Duration Variables

Once created, duration variables can be used anywhere in your styles:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useDuration, useEasing } from '@styleframe/theme';

const s = styleframe();
const { ref, selector, css } = s;

const { durationFast, durationNormal } = useDuration(s, {
    fast: '150ms',
    normal: '250ms',
} as const);

const { easingEaseOutCubic } = useEasing(s, {
    'ease-out-cubic': 'cubic-bezier(0.215, 0.61, 0.355, 1)',
} as const);

selector('.button', {
    transition: css`background-color ${durationFast} ${easingEaseOutCubic}`,
});

selector('.modal', {
    transition: css`opacity ${durationNormal} ${easingEaseOutCubic}, transform ${durationNormal} ${easingEaseOutCubic}`,
});

export default s;

Examples

Semantic Duration Names

Use semantic names to make animation intent clear:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useDuration, durationValues } from '@styleframe/theme';

const s = styleframe();

const {
    duration,
    durationMicro,
    durationUi,
    durationPage,
} = useDuration(s, {
    default: '@ui',
    micro: durationValues.faster,
    ui: durationValues.normal,
    page: durationValues.slow,
} as const);

export default s;

Combined with Easing

Pair duration tokens with easing tokens for a complete motion system:

styleframe.config.ts
import { styleframe } from 'styleframe';
import { useDuration, useEasing } from '@styleframe/theme';

const s = styleframe();
const { selector, css } = s;

const { durationFast, durationNormal, durationSlower } = useDuration(s);
const { easingEaseOut, easingEaseInOut, easingSpring } = useEasing(s);

selector('.tooltip', {
    transition: css`opacity ${durationFast} ${easingEaseOut}`,
});

selector('.dropdown', {
    transition: css`transform ${durationNormal} ${easingEaseInOut}`,
});

selector('.notification', {
    transition: css`transform ${durationSlower} ${easingSpring}`,
});

export default s;

Best Practices

  • Keep micro-interactions fast: Hover and focus effects should use fastest (50ms) to fast (150ms) for responsive feedback.
  • Use the default key: This creates a clean --duration variable that's perfect for general-purpose transitions.
  • Pair with easing tokens: Duration alone doesn't make great animations — combine with useEasing for polished motion.
  • Respect reduced motion: For users who prefer reduced motion, consider overriding durations to 0ms using prefers-reduced-motion.
  • Match duration to distance: Larger movements need longer durations. A tooltip fade needs less time than a full-page transition.
Good to know: We use as const to ensure the object is treated as a constant type. This helps TypeScript infer the return type of the composables and provides better type safety and autocomplete support.

FAQ