Design Tokens

Easing

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

Overview

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

Why use easing composables?

Easing composables help you:

  • Centralize timing functions: Define all your easing curves in one place for easy management.
  • Enable flexible theming: Override easing values to instantly update animations across your application.
  • Maintain consistency: Use semantic names to ensure consistent motion throughout your design system.
  • Access advanced easings: Use spring and bounce effects with the CSS linear() function.

useEasing

The useEasing() function creates a set of easing variables from a simple object of easing value definitions. It includes comprehensive defaults covering CSS keywords, cubic-bezier curves, and linear() functions for spring and bounce effects.

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

const s = styleframe();

const {
    easing,
    easingEaseInOut,
    easingEaseOutCubic,
    easingSpring,
    easingBounce,
} = useEasing(s, {
    default: '@ease-out-cubic',
    'ease-in-out': 'ease-in-out',
    'ease-out-cubic': 'cubic-bezier(0.215, 0.61, 0.355, 1)',
    spring: 'linear(0, 0.0018, 0.0069 1.15%, ...)',
    bounce: 'linear(0, 0.004, 0.016, ...)',
} as const);

export default s;

Each key in the object becomes an easing variable with the prefix easing, and the export name is automatically converted to camelCase (e.g., defaulteasing, ease-out-cubiceasingEaseOutCubic).

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

Default Values

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

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

const s = styleframe();

// Use all defaults
const {
    easingLinear,
    easingEase,
    easingEaseIn,
    easingEaseOut,
    easingEaseInOut,
    easingEaseInSine,
    easingEaseOutCubic,
    easingSpring,
    easingBounce,
    // ... and many more
} = useEasing(s);

export default s;

Basic CSS Keywords

NameValue
linearlinear
easeease
ease-inease-in
ease-outease-out
ease-in-outease-in-out

Cubic-Bezier Easings

Based on easings.net, these provide mathematically precise timing curves:

FamilyEase InEase OutEase In-Out
Sinecubic-bezier(0.47, 0, 0.745, 0.715)cubic-bezier(0.39, 0.575, 0.565, 1)cubic-bezier(0.445, 0.05, 0.55, 0.95)
Quadcubic-bezier(0.55, 0.085, 0.68, 0.53)cubic-bezier(0.25, 0.46, 0.45, 0.94)cubic-bezier(0.455, 0.03, 0.515, 0.955)
Cubiccubic-bezier(0.55, 0.055, 0.675, 0.19)cubic-bezier(0.215, 0.61, 0.355, 1)cubic-bezier(0.645, 0.045, 0.355, 1)
Quartcubic-bezier(0.895, 0.03, 0.685, 0.22)cubic-bezier(0.165, 0.84, 0.44, 1)cubic-bezier(0.77, 0, 0.175, 1)
Quintcubic-bezier(0.755, 0.05, 0.855, 0.06)cubic-bezier(0.23, 1, 0.32, 1)cubic-bezier(0.86, 0, 0.07, 1)
Expocubic-bezier(0.95, 0.05, 0.795, 0.035)cubic-bezier(0.19, 1, 0.22, 1)cubic-bezier(1, 0, 0, 1)
Circcubic-bezier(0.6, 0.04, 0.98, 0.335)cubic-bezier(0.075, 0.82, 0.165, 1)cubic-bezier(0.785, 0.135, 0.15, 0.86)
Backcubic-bezier(0.6, -0.28, 0.735, 0.045)cubic-bezier(0.175, 0.885, 0.32, 1.275)cubic-bezier(0.68, -0.55, 0.265, 1.55)
Back easings include overshoot effects where the animation briefly goes beyond the target value before settling. This creates a more dynamic, bouncy feel.

Spring and Bounce

Based on Josh Comeau's research, these use the CSS linear() function for physics-based animations:

NameDescription
springSimulates a spring with overshoot and settling
bounceSimulates a bouncing effect like a ball hitting the ground
Browser Support: The linear() function is supported in Chrome/Edge 113+, Firefox 112+, and Safari 17.2+. For older browsers, consider providing a cubic-bezier() fallback.

Using Easing Variables

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

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

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

const { easing, easingEaseOutCubic, easingSpring } = useEasing(s, {
    default: '@ease-out-cubic',
    'ease-out-cubic': 'cubic-bezier(0.215, 0.61, 0.355, 1)',
    spring: 'linear(0, 0.0018, 0.0069 1.15%, 0.026 2.3%, 0.0637, 0.1135 5.18%, 0.2229 7.78%, 0.5977 15.84%, 0.7014, 0.7904, 0.8641, 0.9228, 0.9676 28.8%, 1.0032 31.68%, 1.0225, 1.0352 36.29%, 1.0431 38.88%, 1.046 42.05%, 1.0448 44.35%, 1.0407 47.23%, 1.0118 61.63%, 1.0025 69.41%, 0.9981 80.35%, 0.9992 99.94%)',
} as const);

selector('.button', {
    transition: css`transform 0.2s ${ref(easing)}`,
});

selector('.modal', {
    transition: css`opacity 0.3s ${ref(easingEaseOutCubic)}, transform 0.5s ${ref(easingSpring)}`,
});

export default s;

Examples

Semantic Easing Names

Use semantic names to make easing intent clear:

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

const s = styleframe();

const {
    easing,
    easingEnter,
    easingExit,
    easingEmphasize,
} = useEasing(s, {
    default: '@enter',
    enter: defaultEasingValues['ease-out-cubic'],
    exit: defaultEasingValues['ease-in-cubic'],
    emphasize: defaultEasingValues.spring,
} as const);

export default s;

Animation with Keyframes

Combine easing with keyframes for complex animations:

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

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

const { easingBounce, easingSpring } = useEasing(s);

const fadeIn = keyframes('fade-in', {
    '0%': { opacity: 0, transform: 'translateY(-20px)' },
    '100%': { opacity: 1, transform: 'translateY(0)' },
});

selector('.notification', {
    animation: css`${fadeIn} 0.5s ${ref(easingBounce)} forwards`,
});

selector('.tooltip', {
    animation: css`${fadeIn} 0.3s ${ref(easingSpring)} forwards`,
});

export default s;

Best Practices

  • Start with sensible defaults: Use ease-out for entrances and ease-in for exits.
  • Use the default key: This creates a clean --easing variable that's perfect for general-purpose animations.
  • Choose appropriate curves: Use ease-out-cubic or ease-out-quart for UI interactions, and reserve spring and bounce for emphasis.
  • Consider performance: Complex linear() functions with many stops may impact performance on low-end devices.
  • Provide fallbacks: For browsers that don't support linear(), consider providing cubic-bezier() fallbacks.
  • Keep it subtle: Most UI animations should be quick (150-300ms) with gentle easing.
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