Design Tokens

Design Tokens Presets

Quickly bootstrap a complete design token system with sensible defaults using the useDesignTokensPreset composable.

Overview

The useDesignTokensPreset composable creates a complete design token system with sensible defaults in a single function call. It's perfect for quickly bootstrapping a new project or as a starting point that you can customize.

Why use presets?

  • Quick Start: Get a complete design system up and running in seconds
  • Sensible Defaults: Carefully chosen values that work well together
  • Fully Customizable: Override any domain or individual value
  • Comprehensive Coverage: Includes spacing, colors, typography, borders, shadows, and more

Quick Start

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

const s = styleframe();

// Create a complete design token system with all defaults
const preset = useDesignTokensPreset(s);

// Destructure the variables you need directly
const { colorPrimary, colorSecondary, spacingMd, spacingLg } = preset;

export default s;

useDesignTokensPreset

Creates a complete design token system with customizable defaults.

Signature

function useDesignTokensPreset(
    s: Styleframe,
    config?: DesignTokensPresetConfig
): DesignTokensPresetResult

Configuration Options

Each domain can be configured as:

  • Omitted/undefined (default): Use the preset's default values
  • false: Skip this domain entirely
  • Record<string, TokenValue>: Use custom values
OptionTypeDescription
spacingfalse | Record<string, TokenValue>Spacing tokens (padding, margin, gap)
borderWidthfalse | Record<string, TokenValue>Border width tokens
borderRadiusfalse | Record<string, TokenValue>Border radius tokens
borderStylefalse | Record<string, TokenValue>Border style tokens
boxShadowfalse | Record<string, TokenValue>Box shadow elevation tokens
zIndexfalse | Record<string, TokenValue>Z-index stacking order tokens
colorsfalse | Record<string, string>Semantic color tokens
meta.colorsColorsMetaConfigColor generation options
fontFamilyfalse | Record<string, TokenValue>Font family tokens
fontSizefalse | Record<string, TokenValue | [min, max]>Font size tokens. When fluidFontSize is enabled (default), overrides the fluid defaults for provided keys; tuple values [min, max] produce calc() fluid expressions (pass fluidFontSize: false to use purely static values)
fontStylefalse | Record<string, TokenValue>Font style tokens
fontWeightfalse | Record<string, TokenValue>Font weight tokens
lineHeightfalse | Record<string, TokenValue>Line height tokens
letterSpacingfalse | Record<string, TokenValue>Letter spacing tokens
scalefalse | Record<string, TokenValue>Modular scale ratios (must include default key referencing scale for scalePowers)
scalePowersreadonly number[]Scale power levels
breakpointfalse | Record<string, number>Responsive breakpoints
easingfalse | Record<string, TokenValue>Animation easing functions
fluidViewportfalse | true | { minWidth?, maxWidth? }Fluid viewport range powering fluid.breakpoint (see Fluid Typography)
fluidFontSizefalse | trueViewport-responsive font-size scale. Enabled by default; depends on scale and fluidViewport. Pass false to fall back to static fontSize (see Fluid Typography)
fluidScale{ min?, max? }Min/max scale ratios driving the default fluid font sizes (consumed when fluidFontSize is not disabled)
themesRecord<string, ThemeTokenOverrides>Per-theme token overrides (see Themes)

Default Values

Border Radius

const preset = useDesignTokensPreset(s);
const {
    borderRadius,     // Variable<'border-radius'>
    borderRadiusNone, // Variable<'border-radius.none'>
    borderRadiusSm,   // Variable<'border-radius.sm'>
    borderRadiusMd,   // Variable<'border-radius.md'>
    borderRadiusLg,   // Variable<'border-radius.lg'>
    borderRadiusXl,   // Variable<'border-radius.xl'>
    borderRadius2xl,  // Variable<'border-radius.2xl'>
    borderRadiusFull, // Variable<'border-radius.full'>
} = preset;
KeyValueVariableOutput
default@border-radius.mdborderRadius--border-radius
none0borderRadiusNone--border-radius--none
sm0.125remborderRadiusSm--border-radius--sm
md0.25remborderRadiusMd--border-radius--md
lg0.5remborderRadiusLg--border-radius--lg
xl0.75remborderRadiusXl--border-radius--xl
2xl1remborderRadius2xl--border-radius--2xl
full9999pxborderRadiusFull--border-radius--full

Border Style

const preset = useDesignTokensPreset(s);
const {
    borderStyle,       // Variable<'border-style'>
    borderStyleNone,   // Variable<'border-style.none'>
    borderStyleSolid,  // Variable<'border-style.solid'>
    borderStyleDashed, // Variable<'border-style.dashed'>
    borderStyleDotted, // Variable<'border-style.dotted'>
    borderStyleDouble, // Variable<'border-style.double'>
    borderStyleGroove, // Variable<'border-style.groove'>
    borderStyleInset,  // Variable<'border-style.inset'>
    borderStyleOutset, // Variable<'border-style.outset'>
} = preset;
KeyValueVariableOutput
default@border-style.solidborderStyle--border-style
nonenoneborderStyleNone--border-style--none
solidsolidborderStyleSolid--border-style--solid
dasheddashedborderStyleDashed--border-style--dashed
dotteddottedborderStyleDotted--border-style--dotted
doubledoubleborderStyleDouble--border-style--double
groovegrooveborderStyleGroove--border-style--groove
insetinsetborderStyleInset--border-style--inset
outsetoutsetborderStyleOutset--border-style--outset

Border Width

const preset = useDesignTokensPreset(s);
const {
    borderWidth,       // Variable<'border-width'>
    borderWidthNone,   // Variable<'border-width.none'>
    borderWidthThin,   // Variable<'border-width.thin'>
    borderWidthMedium, // Variable<'border-width.medium'>
    borderWidthThick,  // Variable<'border-width.thick'>
} = preset;
KeyValueVariableOutput
default@border-width.thinborderWidth--border-width
none0borderWidthNone--border-width--none
thinthinborderWidthThin--border-width--thin
mediummediumborderWidthMedium--border-width--medium
thickthickborderWidthThick--border-width--thick

Box Shadow

const preset = useDesignTokensPreset(s);
const {
    boxShadow,      // Variable<'box-shadow'>
    boxShadowNone,  // Variable<'box-shadow.none'>
    boxShadowXs,    // Variable<'box-shadow.xs'>
    boxShadowSm,    // Variable<'box-shadow.sm'>
    boxShadowMd,    // Variable<'box-shadow.md'>
    boxShadowLg,    // Variable<'box-shadow.lg'>
    boxShadowXl,    // Variable<'box-shadow.xl'>
    boxShadow2xl,   // Variable<'box-shadow.2xl'>
    boxShadowInner, // Variable<'box-shadow.inner'>
    boxShadowRing,  // Variable<'box-shadow.ring'>
} = preset;
KeyValueVariableOutput
default@box-shadow.mdboxShadow--box-shadow
nonenoneboxShadowNone--box-shadow--none
xsSubtle card/surfaces shadowboxShadowXs--box-shadow--xs
smSmall elevation shadowboxShadowSm--box-shadow--sm
mdPopover/raised button shadowboxShadowMd--box-shadow--md
lgModal/floating panel shadowboxShadowLg--box-shadow--lg
xlDrawer/high elevation shadowboxShadowXl--box-shadow--xl
2xlHighest elevation/toast shadowboxShadow2xl--box-shadow--2xl
innerInset shadow for wellsboxShadowInner--box-shadow--inner
ringFocus ring shadowboxShadowRing--box-shadow--ring

Z-Index

const preset = useDesignTokensPreset(s);
const {
    zIndex,         // Variable<'z-index'>
    zIndexHide,     // Variable<'z-index.hide'>
    zIndexBase,     // Variable<'z-index.base'>
    zIndexDropdown, // Variable<'z-index.dropdown'>
    zIndexSticky,   // Variable<'z-index.sticky'>
    zIndexOverlay,  // Variable<'z-index.overlay'>
    zIndexModal,    // Variable<'z-index.modal'>
    zIndexPopover,  // Variable<'z-index.popover'>
    zIndexToast,    // Variable<'z-index.toast'>
    zIndexMax,      // Variable<'z-index.max'>
    zIndexAuto,     // Variable<'z-index.auto'>
} = preset;
KeyValueVariableOutput
default@z-index.basezIndex--z-index
hide-1zIndexHide--z-index--hide
base0zIndexBase--z-index--base
dropdown100zIndexDropdown--z-index--dropdown
sticky200zIndexSticky--z-index--sticky
overlay300zIndexOverlay--z-index--overlay
modal400zIndexModal--z-index--modal
popover500zIndexPopover--z-index--popover
toast600zIndexToast--z-index--toast
max9999zIndexMax--z-index--max
autoautozIndexAuto--z-index--auto

Breakpoint

const preset = useDesignTokensPreset(s);
const {
    breakpointXs,  // Variable<'breakpoint.xs'>
    breakpointSm,  // Variable<'breakpoint.sm'>
    breakpointMd,  // Variable<'breakpoint.md'>
    breakpointLg,  // Variable<'breakpoint.lg'>
    breakpointXl,  // Variable<'breakpoint.xl'>
    breakpoint2xl, // Variable<'breakpoint.2xl'>
} = preset;
KeyValue (px)VariableOutput
xs0breakpointXs--breakpoint--xs
sm576breakpointSm--breakpoint--sm
md768breakpointMd--breakpoint--md
lg992breakpointLg--breakpoint--lg
xl1200breakpointXl--breakpoint--xl
2xl1440breakpoint2xl--breakpoint--2xl

Colors

const preset = useDesignTokensPreset(s);
const {
    colorPrimary,   // Variable<'color.primary'>
    colorSecondary, // Variable<'color.secondary'>
    colorSuccess,   // Variable<'color.success'>
    colorWarning,   // Variable<'color.warning'>
    colorError,    // Variable<'color.error'>
    colorInfo,      // Variable<'color.info'>
    colorLight,     // Variable<'color.light'>
    colorDark,      // Variable<'color.dark'>
} = preset;
KeyValueVariableOutput
primary#3b82f6colorPrimary--color--primary
secondary#6b7280colorSecondary--color--secondary
success#22c55ecolorSuccess--color--success
warning#f59e0bcolorWarning--color--warning
error#ef4444colorError--color--error
info#06b6d4colorInfo--color--info
light#f8fafccolorLight--color--light
dark#1e293bcolorDark--color--dark

By default, each color also generates:

  • Levels: 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950
  • Shades (darker): shade-50, shade-100, shade-150, shade-200
  • Tints (lighter): tint-50, tint-100, tint-150, tint-200

Color Generation Options

The meta.colors option controls how color variations are generated:

OptionTypeDefaultDescription
generateLevelsbooleantrueGenerate levels (50-950)
generateShadesbooleantrueGenerate darker shades
generateTintsbooleantrueGenerate lighter tints
levelsRecord<string | number, number>{ 50: 5, 100: 10, ... }Custom levels
shadeLevelsRecord<string | number, number>{ "shade-50": 5, "shade-100": 10, ... }Custom shade levels
tintLevelsRecord<string | number, number>{ "tint-50": 5, "tint-100": 10, ... }Custom tint levels

Easing

const preset = useDesignTokensPreset(s);
const {
    easingLinear,       // Variable<'easing.linear'>
    easingEase,         // Variable<'easing.ease'>
    easingEaseIn,       // Variable<'easing.ease-in'>
    easingEaseOut,      // Variable<'easing.ease-out'>
    easingEaseInOut,    // Variable<'easing.ease-in-out'>
    easingEaseInSine,   // Variable<'easing.ease-in-sine'>
    easingEaseOutCubic, // Variable<'easing.ease-out-cubic'>
    easingSpring,       // Variable<'easing.spring'>
    easingBounce,       // Variable<'easing.bounce'>
} = preset;

Basic CSS Keywords:

KeyValueVariableOutput
linearlineareasingLinear--easing--linear
easeeaseeasingEase--easing--ease
ease-inease-ineasingEaseIn--easing--ease-in
ease-outease-outeasingEaseOut--easing--ease-out
ease-in-outease-in-outeasingEaseInOut--easing--ease-in-out

Sine:

KeyValueVariableOutput
ease-in-sinecubic-bezier(0.47, 0, 0.745, 0.715)easingEaseInSine--easing--ease-in-sine
ease-out-sinecubic-bezier(0.39, 0.575, 0.565, 1)easingEaseOutSine--easing--ease-out-sine
ease-in-out-sinecubic-bezier(0.445, 0.05, 0.55, 0.95)easingEaseInOutSine--easing--ease-in-out-sine

Quad:

KeyValueVariableOutput
ease-in-quadcubic-bezier(0.55, 0.085, 0.68, 0.53)easingEaseInQuad--easing--ease-in-quad
ease-out-quadcubic-bezier(0.25, 0.46, 0.45, 0.94)easingEaseOutQuad--easing--ease-out-quad
ease-in-out-quadcubic-bezier(0.455, 0.03, 0.515, 0.955)easingEaseInOutQuad--easing--ease-in-out-quad

Cubic:

KeyValueVariableOutput
ease-in-cubiccubic-bezier(0.55, 0.055, 0.675, 0.19)easingEaseInCubic--easing--ease-in-cubic
ease-out-cubiccubic-bezier(0.215, 0.61, 0.355, 1)easingEaseOutCubic--easing--ease-out-cubic
ease-in-out-cubiccubic-bezier(0.645, 0.045, 0.355, 1)easingEaseInOutCubic--easing--ease-in-out-cubic

Quart:

KeyValueVariableOutput
ease-in-quartcubic-bezier(0.895, 0.03, 0.685, 0.22)easingEaseInQuart--easing--ease-in-quart
ease-out-quartcubic-bezier(0.165, 0.84, 0.44, 1)easingEaseOutQuart--easing--ease-out-quart
ease-in-out-quartcubic-bezier(0.77, 0, 0.175, 1)easingEaseInOutQuart--easing--ease-in-out-quart

Quint:

KeyValueVariableOutput
ease-in-quintcubic-bezier(0.755, 0.05, 0.855, 0.06)easingEaseInQuint--easing--ease-in-quint
ease-out-quintcubic-bezier(0.23, 1, 0.32, 1)easingEaseOutQuint--easing--ease-out-quint
ease-in-out-quintcubic-bezier(0.86, 0, 0.07, 1)easingEaseInOutQuint--easing--ease-in-out-quint

Expo:

KeyValueVariableOutput
ease-in-expocubic-bezier(0.95, 0.05, 0.795, 0.035)easingEaseInExpo--easing--ease-in-expo
ease-out-expocubic-bezier(0.19, 1, 0.22, 1)easingEaseOutExpo--easing--ease-out-expo
ease-in-out-expocubic-bezier(1, 0, 0, 1)easingEaseInOutExpo--easing--ease-in-out-expo

Circ:

KeyValueVariableOutput
ease-in-circcubic-bezier(0.6, 0.04, 0.98, 0.335)easingEaseInCirc--easing--ease-in-circ
ease-out-circcubic-bezier(0.075, 0.82, 0.165, 1)easingEaseOutCirc--easing--ease-out-circ
ease-in-out-circcubic-bezier(0.785, 0.135, 0.15, 0.86)easingEaseInOutCirc--easing--ease-in-out-circ

Back (with overshoot):

KeyValueVariableOutput
ease-in-backcubic-bezier(0.6, -0.28, 0.735, 0.045)easingEaseInBack--easing--ease-in-back
ease-out-backcubic-bezier(0.175, 0.885, 0.32, 1.275)easingEaseOutBack--easing--ease-out-back
ease-in-out-backcubic-bezier(0.68, -0.55, 0.265, 1.55)easingEaseInOutBack--easing--ease-in-out-back

Special (linear() functions):

KeyDescriptionVariableOutput
springNatural spring animationeasingSpring--easing--spring
bounceBouncy animation effecteasingBounce--easing--bounce

Font Family

const preset = useDesignTokensPreset(s);
const {
    fontFamily,      // Variable<'font-family'>
    fontFamilyBase,  // Variable<'font-family.base'>
    fontFamilyPrint, // Variable<'font-family.print'>
    fontFamilyMono,  // Variable<'font-family.mono'>
} = preset;
KeyValueVariableOutput
default@font-family.basefontFamily--font-family
baseSystem font stack (sans-serif)fontFamilyBase--font-family--base
printGeorgia, Times New Roman (serif)fontFamilyPrint--font-family--print
monoSFMono-Regular, Menlo (monospace)fontFamilyMono--font-family--mono

Font Size

const preset = useDesignTokensPreset(s);
const {
    fontSize,    // Variable<'font-size'>
    fontSizeXs,  // Variable<'font-size.xs'>
    fontSizeSm,  // Variable<'font-size.sm'>
    fontSizeMd,  // Variable<'font-size.md'>
    fontSizeLg,  // Variable<'font-size.lg'>
    fontSizeXl,  // Variable<'font-size.xl'>
    fontSize2xl, // Variable<'font-size.2xl'>
    fontSize3xl, // Variable<'font-size.3xl'>
    fontSize4xl, // Variable<'font-size.4xl'>
} = preset;
KeyValueVariableOutput
default@font-size.mdfontSize--font-size
xs0.75remfontSizeXs--font-size--xs
sm0.875remfontSizeSm--font-size--sm
md1remfontSizeMd--font-size--md
lg1.125remfontSizeLg--font-size--lg
xl1.25remfontSizeXl--font-size--xl
2xl1.5remfontSize2xl--font-size--2xl
3xl1.875remfontSize3xl--font-size--3xl
4xl2.25remfontSize4xl--font-size--4xl

Fluid Typography

Fluid typography is enabled by default. The preset emits fluid.* viewport variables, configurable base variables (--font-size--min: 16 / --font-size--max: 18), and configures useFontSizeDesignTokens() with fluid pixel ranges, so every font-size.* variable becomes a calc() that interpolates between a min and max as the viewport scales. To opt out and use static font sizes, pass fluidFontSize: false. Any sizes you pass under fontSize override the fluid defaults for those keys.

// Fluid is the default — no opt-in needed
const preset = useDesignTokensPreset(s);
const {
    fluidBreakpoint,    // Variable<'fluid.breakpoint'>
    fluidMinWidth,      // Variable<'fluid.min-width'>
    fluidMaxWidth,      // Variable<'fluid.max-width'>
    fluidScreen,        // Variable<'fluid.screen'>
    fontSize,           // Variable<'font-size'>
    fontSizeMd,         // Variable<'font-size.md'>
    // ...all standard font-size keys
} = preset;

Default fluid viewport

fluidViewport defines the viewport range across which fluid values interpolate.

KeyDefaultVariableOutput
minWidth320fluidMinWidth--fluid--min-width
maxWidth1440fluidMaxWidth--fluid--max-width
(constant)100vwfluidScreen--fluid--screen
(computed)calc(...)fluidBreakpoint--fluid--breakpoint

Default fluid scale

fluidScale defines the modular scale ratios used to compute the default fluid font sizes. The preset materializes both ratios as variables along with their per-step powers (scale.min-powers.<n> / scale.max-powers.<n>), so the default font-size values are scale-driven rather than hand-tuned numbers.

KeyDefaultVariableOutput
min@scale.major-second (1.125)scaleMin--scale--min
max@scale.major-third (1.25)scaleMax--scale--max
(per power)1, var(--scale--min), var(--scale--min) * var(--scale--min), …(internal)--scale--min-powers--<n>
(per power)1, var(--scale--max), var(--scale--max) * var(--scale--max), …(internal)--scale--max-powers--<n>

Override the ratios with fluidScale: { min: <ratio>, max: <ratio> } to rescale every default font-size step at once. Pass numbers (e.g., 1.067) or @scale.<name> references.

Default fluid font size

When fluidFontSize is enabled (the default), the preset emits two configurable CSS variables for the base pixel range — --font-size--min: 16 and --font-size--max: 18. Each named font-size step then interpolates between var(--font-size--min) and var(--font-size--max), scaled by the step's modular-scale power (scale.min-powers.<n> / scale.max-powers.<n>). The min/max ratios come from fluidScale.

To retarget the base, override --font-size--min and --font-size--max in your own stylesheet (or via fontSize: { min: 14, max: 20 } with meta: { merge: true }). To override individual steps, pass explicit [min, max] tuples via fontSize (e.g. fontSize: { md: [14, 18] }).

KeyStepValue (default)VariableOutput
min16 (configurable fluid base)fontSizeMin--font-size--min
max18 (configurable fluid base)fontSizeMax--font-size--max
default@font-size.mdfontSize--font-size
3xs-4[@font-size.min * @scale.min-powers.-4, @font-size.max * @scale.max-powers.-4]fontSize3xs--font-size--3xs
2xs-3[@font-size.min * @scale.min-powers.-3, @font-size.max * @scale.max-powers.-3]fontSize2xs--font-size--2xs
xs-2[@font-size.min * @scale.min-powers.-2, @font-size.max * @scale.max-powers.-2]fontSizeXs--font-size--xs
sm-1[@font-size.min * @scale.min-powers.-1, @font-size.max * @scale.max-powers.-1]fontSizeSm--font-size--sm
md0[@font-size.min * @scale.min-powers.0, @font-size.max * @scale.max-powers.0]fontSizeMd--font-size--md
lg1[@font-size.min * @scale.min-powers.1, @font-size.max * @scale.max-powers.1]fontSizeLg--font-size--lg
xl2[@font-size.min * @scale.min-powers.2, @font-size.max * @scale.max-powers.2]fontSizeXl--font-size--xl
2xl3[@font-size.min * @scale.min-powers.3, @font-size.max * @scale.max-powers.3]fontSize2xl--font-size--2xl
3xl4[@font-size.min * @scale.min-powers.4, @font-size.max * @scale.max-powers.4]fontSize3xl--font-size--3xl
4xl5[@font-size.min * @scale.min-powers.5, @font-size.max * @scale.max-powers.5]fontSize4xl--font-size--4xl

You can override individual steps with literal pixel range tuples (e.g., lg: [18, 22]) — those bypass the scale entirely. See Customizing Fluid Typography for runnable examples and the hybrid (per-key) pattern.

Font Style

const preset = useDesignTokensPreset(s);
const {
    fontStyle,        // Variable<'font-style'>
    fontStyleItalic,  // Variable<'font-style.italic'>
    fontStyleOblique, // Variable<'font-style.oblique'>
    fontStyleNormal,  // Variable<'font-style.normal'>
    fontStyleInherit, // Variable<'font-style.inherit'>
} = preset;
KeyValueVariableOutput
default@font-style.normalfontStyle--font-style
italicitalicfontStyleItalic--font-style--italic
obliqueobliquefontStyleOblique--font-style--oblique
normalnormalfontStyleNormal--font-style--normal
inheritinheritfontStyleInherit--font-style--inherit

Font Weight

const preset = useDesignTokensPreset(s);
const {
    fontWeight,           // Variable<'font-weight'>
    fontWeightExtralight, // Variable<'font-weight.extralight'>
    fontWeightLight,      // Variable<'font-weight.light'>
    fontWeightNormal,     // Variable<'font-weight.normal'>
    fontWeightMedium,     // Variable<'font-weight.medium'>
    fontWeightSemibold,   // Variable<'font-weight.semibold'>
    fontWeightBold,       // Variable<'font-weight.bold'>
    fontWeightBlack,      // Variable<'font-weight.black'>
    fontWeightLighter,    // Variable<'font-weight.lighter'>
    fontWeightBolder,     // Variable<'font-weight.bolder'>
    fontWeightInherit,    // Variable<'font-weight.inherit'>
} = preset;
KeyValueVariableOutput
default@font-weight.normalfontWeight--font-weight
extralight200fontWeightExtralight--font-weight--extralight
light300fontWeightLight--font-weight--light
normalnormalfontWeightNormal--font-weight--normal
medium500fontWeightMedium--font-weight--medium
semibold600fontWeightSemibold--font-weight--semibold
boldboldfontWeightBold--font-weight--bold
black900fontWeightBlack--font-weight--black
lighterlighterfontWeightLighter--font-weight--lighter
bolderbolderfontWeightBolder--font-weight--bolder
inheritinheritfontWeightInherit--font-weight--inherit

Letter Spacing

const preset = useDesignTokensPreset(s);
const {
    letterSpacing,        // Variable<'letter-spacing'>
    letterSpacingTighter, // Variable<'letter-spacing.tighter'>
    letterSpacingTight,   // Variable<'letter-spacing.tight'>
    letterSpacingNormal,  // Variable<'letter-spacing.normal'>
    letterSpacingWide,    // Variable<'letter-spacing.wide'>
    letterSpacingWider,   // Variable<'letter-spacing.wider'>
} = preset;
KeyValueVariableOutput
default@letter-spacing.normalletterSpacing--letter-spacing
tighter-0.05emletterSpacingTighter--letter-spacing--tighter
tight-0.025emletterSpacingTight--letter-spacing--tight
normalnormalletterSpacingNormal--letter-spacing--normal
wide0.05emletterSpacingWide--letter-spacing--wide
wider0.1emletterSpacingWider--letter-spacing--wider

Line Height

const preset = useDesignTokensPreset(s);
const {
    lineHeight,        // Variable<'line-height'>
    lineHeightTight,   // Variable<'line-height.tight'>
    lineHeightSnug,    // Variable<'line-height.snug'>
    lineHeightNormal,  // Variable<'line-height.normal'>
    lineHeightRelaxed, // Variable<'line-height.relaxed'>
    lineHeightLoose,   // Variable<'line-height.loose'>
} = preset;
KeyValueVariableOutput
default@line-height.normallineHeight--line-height
tight1.2lineHeightTight--line-height--tight
snug1.35lineHeightSnug--line-height--snug
normal1.5lineHeightNormal--line-height--normal
relaxed1.65lineHeightRelaxed--line-height--relaxed
loose1.9lineHeightLoose--line-height--loose

Scale

const preset = useDesignTokensPreset(s);
const {
    scale,                // Variable<'scale'>
    scaleMinorSecond,     // Variable<'scale.minor-second'>
    scaleMajorSecond,     // Variable<'scale.major-second'>
    scaleMinorThird,      // Variable<'scale.minor-third'>
    scaleMajorThird,      // Variable<'scale.major-third'>
    scalePerfectFourth,   // Variable<'scale.perfect-fourth'>
    scaleAugmentedFourth, // Variable<'scale.augmented-fourth'>
    scalePerfectFifth,    // Variable<'scale.perfect-fifth'>
    scaleGolden,          // Variable<'scale.golden'>
} = preset;
KeyValueVariableOutput
default@scale.minor-thirdscale--scale
minor-second1.067scaleMinorSecond--scale--minor-second
major-second1.125scaleMajorSecond--scale--major-second
minor-third1.2scaleMinorThird--scale--minor-third
major-third1.25scaleMajorThird--scale--major-third
perfect-fourth1.333scalePerfectFourth--scale--perfect-fourth
augmented-fourth1.414scaleAugmentedFourth--scale--augmented-fourth
perfect-fifth1.5scalePerfectFifth--scale--perfect-fifth
golden1.618scaleGolden--scale--golden

Scale Powers

The preset generates scale power values using the default scale variable. These are computed values based on the scale ratio.

const preset = useDesignTokensPreset(s);
// Access computed scale powers
const { scalePowers } = preset;
// Returns: { -2: CSS, -1: CSS, 0: CSS, 1: CSS, 2: CSS, 3: CSS, 4: CSS, 5: CSS }
PowerFormulaOutput
-21 / scale / scale--scale-power---2
-11 / scale--scale-power---1
01--scale-power--0
1scale--scale-power--1
2scale * scale--scale-power--2
3scale * scale * scale--scale-power--3
4scale * scale * scale * scale--scale-power--4
5scale * scale * scale * scale * scale--scale-power--5

Spacing

const preset = useDesignTokensPreset(s);
const {
    spacing,    // Variable<'spacing'>
    spacing2xs, // Variable<'spacing.2xs'>
    spacingXs,  // Variable<'spacing.xs'>
    spacingSm,  // Variable<'spacing.sm'>
    spacingMd,  // Variable<'spacing.md'>
    spacingLg,  // Variable<'spacing.lg'>
    spacingXl,  // Variable<'spacing.xl'>
    spacing2xl, // Variable<'spacing.2xl'>
    spacing3xl, // Variable<'spacing.3xl'>
} = preset;
KeyValueVariableOutput
default@spacing.mdspacing--spacing
2xs0.25remspacing2xs--spacing--2xs
xs0.5remspacingXs--spacing--xs
sm0.75remspacingSm--spacing--sm
md1remspacingMd--spacing--md
lg1.5remspacingLg--spacing--lg
xl2remspacingXl--spacing--xl
2xl3remspacing2xl--spacing--2xl
3xl4remspacing3xl--spacing--3xl

Examples

Full Customization

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

const s = styleframe();

const preset = useDesignTokensPreset(s, {
    // Spacing
    spacing: {
        default: '@spacing.md',
        xs: '0.25rem',
        sm: '0.5rem',
        md: '1rem',
        lg: '2rem',
        xl: '4rem',
    },

    // Border
    borderWidth: {
        default: '@border-width.thin',
        none: '0',
        thin: '1px',
        medium: '2px',
        thick: '4px',
    },
    borderRadius: {
        default: '@border-radius.md',
        none: '0',
        sm: '0.125rem',
        md: '0.25rem',
        lg: '0.5rem',
        full: '9999px',
    },
    borderStyle: {
        default: '@border-style.solid',
        none: 'none',
        solid: 'solid',
        dashed: 'dashed',
        dotted: 'dotted',
    },

    // Shadows
    boxShadow: {
        default: '@box-shadow.md',
        none: 'none',
        sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
        md: '0 4px 6px -1px rgb(0 0 0 / 0.1)',
        lg: '0 10px 15px -3px rgb(0 0 0 / 0.1)',
    },

    // Colors
    colors: {
        primary: '#0066cc',
        secondary: '#6c757d',
        success: '#28a745',
        warning: '#ffc107',
        error: '#dc3545',
        info: '#17a2b8',
        light: '#f8f9fa',
        dark: '#343a40',
    },
    meta: {
        colors: {
            generateLevels: true,
            generateShades: true,
            generateTints: true,
        },
    },

    // Typography
    fontFamily: {
        default: '@font-family.base',
        base: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
        mono: 'SFMono-Regular, Menlo, Monaco, monospace',
    },
    fontSize: {
        default: '@font-size.md',
        xs: '0.75rem',
        sm: '0.875rem',
        md: '1rem',
        lg: '1.25rem',
        xl: '1.5rem',
        '2xl': '2rem',
    },
    fontWeight: {
        default: '@font-weight.normal',
        light: '300',
        normal: '400',
        medium: '500',
        semibold: '600',
        bold: '700',
    },
    lineHeight: {
        default: '@line-height.normal',
        tight: '1.25',
        normal: '1.5',
        relaxed: '1.75',
    },
    letterSpacing: {
        default: '@letter-spacing.normal',
        tight: '-0.025em',
        normal: '0',
        wide: '0.025em',
    },

    // Scale
    scale: {
        default: '@scale.minor-third',
        'minor-second': '1.067',
        'major-second': '1.125',
        'minor-third': '1.2',
        'major-third': '1.25',
        'perfect-fourth': '1.333',
    },

    // Breakpoints
    breakpoint: {
        xs: 0,
        sm: 576,
        md: 768,
        lg: 992,
        xl: 1200,
        '2xl': 1440,
    },

    // Animations
    easing: {
        linear: 'linear',
        ease: 'ease',
        'ease-in': 'ease-in',
        'ease-out': 'ease-out',
        'ease-in-out': 'ease-in-out',
    },
});

export default s;

Disabling Specific Domains

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

const s = styleframe();

// Only include colors, spacing, and typography
const preset = useDesignTokensPreset(s, {
    borderWidth: false,
    borderRadius: false,
    borderStyle: false,
    boxShadow: false,
    scale: false,
    breakpoint: false,
    easing: false,
});

const { colorPrimary, spacingMd } = preset;

export default s;

Customizing Fluid Typography

Fluid typography runs by default. Use the tabs below to customize the viewport range, modular scale, and per-step values — or to opt back into static font sizes.

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

const s = styleframe();

// Defaults — viewport range 320–1440px, base --font-size--min: 16 /
// --font-size--max: 18, `font-size.*` becomes calc() expressions that
// scale with the viewport. No config required.
const preset = useDesignTokensPreset(s);

const { fontSizeMd, fontSizeLg } = preset;

export default s;
Switching modes: the static fontSize domain is auto-replaced by fluid by default. Passing both fontSize and the default fluid scale is allowed but the static config is silently ignored to avoid duplicate font-size.* variables. To use a custom static scale, set fluidFontSize: false. Setting fluidViewport: false (or scale: false) without also disabling fluidFontSize throws a configuration error — the fluid font-size scale depends on both, so the preset surfaces invalid combinations up front instead of producing partial output.

Accessing Generated Variables

import { styleframe } from 'styleframe';
import { useDesignTokensPreset } from '@styleframe/theme';

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

const preset = useDesignTokensPreset(s);

// Destructure the variables you need directly
const {
    spacingMd,
    colorPrimary,
    colorPrimary600,
    borderRadiusMd,
    fontWeightSemibold,
    boxShadowSm,
} = preset;

// Use the generated variables in your styles
selector('.button', {
    padding: ref(spacingMd),
    backgroundColor: ref(colorPrimary),
    borderRadius: ref(borderRadiusMd),
    fontWeight: ref(fontWeightSemibold),
    boxShadow: ref(boxShadowSm),
});

selector('.button:hover', {
    backgroundColor: ref(colorPrimary600),
});

export default s;

Importing Default Values

You can import the default value objects directly if you need to reference them or build upon them:

import { styleframe } from 'styleframe';
import {
    useDesignTokensPreset,
    // Import default values
    defaultSpacingValues,
    defaultColorValues,
    defaultBorderRadiusValues,
} from '@styleframe/theme';

const s = styleframe();

// Partial overrides merge with defaults by default — no spread required
const preset = useDesignTokensPreset(s, {
    spacing: {
        '4xl': '6rem', // Adds a new size on top of all default spacing values
    },
});

export default s;

Available Default Value Exports

ExportDescription
defaultSpacingValuesSpacing scale values
defaultBorderWidthValuesBorder width values
defaultBorderRadiusValuesBorder radius values
defaultBorderStyleValuesBorder style values
defaultBoxShadowValuesBox shadow elevation values
defaultColorValuesSemantic color values
colorLevelValuesLevel values
defaultColorShadeValuesShade level values
defaultColorTintValuesTint level values
defaultFontFamilyValuesFont family values
defaultFontSizeValuesFont size scale values
defaultFontStyleValuesFont style values
defaultFontWeightValuesFont weight values
defaultLineHeightValuesLine height values
defaultLetterSpacingValuesLetter spacing values
defaultScaleValuesModular scale ratio values
defaultScalePowerValuesScale power levels
defaultBreakpointValuesResponsive breakpoint values
defaultEasingValuesAnimation easing function values
defaultColorsMetaConfigDefault color generation configuration

Themes

The themes option lets you define per-theme token overrides directly in the preset. Each theme generates a [data-theme="name"] block that overrides the root-level tokens.

Dark Mode

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

const s = styleframe();

const preset = useDesignTokensPreset(s, {
    colors: {
        primary: '#007bff',
        secondary: '#6c757d',
    },
    themes: {
        dark: {
            colors: {
                primary: '#60a5fa',
                secondary: '#cbd5e1',
            },
        },
    },
});

export default s;

Multiple Themes

You can define multiple themes at once. Each theme can override any domain (colors, spacing, typography, etc.):

const preset = useDesignTokensPreset(s, {
    colors: { primary: '#007bff' },
    spacing: { default: '@spacing.md', sm: '0.5rem', md: '1rem', lg: '2rem' },
    themes: {
        dark: {
            colors: { primary: '#60a5fa' },
        },
        compact: {
            spacing: { default: '0.75rem', sm: '0.25rem', lg: '1.5rem' },
        },
        high_contrast: {
            colors: { primary: '#0000ff' },
        },
    },
});

Default Theme

The special themes.default key does not create a [data-theme="default"] block. Instead, it provides fallback values for undefined root-level config:

const preset = useDesignTokensPreset(s, {
    // No root-level colors or spacing defined
    themes: {
        default: {
            colors: { primary: '#ff6600', secondary: '#333' },
            spacing: { default: '0.5rem', sm: '0.25rem' },
        },
        dark: {
            colors: { primary: '#60a5fa' },
        },
    },
});

// Colors and spacing are created at :root from themes.default
// Only "dark" gets a [data-theme="dark"] block

Root-level config always takes precedence over themes.default:

const preset = useDesignTokensPreset(s, {
    colors: { brand: '#ff0000' },  // This wins
    themes: {
        default: {
            colors: { primary: '#007bff' },  // Ignored (root-level colors defined)
        },
    },
});

Theme Overrides Interface

Each theme can override any of the following domains:

DomainType
spacingRecord<string, TokenValue>
borderWidthRecord<string, TokenValue>
borderRadiusRecord<string, TokenValue>
borderStyleRecord<string, TokenValue>
boxShadowRecord<string, TokenValue>
colorsRecord<string, string>
fontFamilyRecord<string, TokenValue>
fontSizeRecord<string, TokenValue>
fontStyleRecord<string, TokenValue>
fontWeightRecord<string, TokenValue>
lineHeightRecord<string, TokenValue>
letterSpacingRecord<string, TokenValue>
scaleRecord<string, TokenValue>
breakpointRecord<string, number>
easingRecord<string, TokenValue>

Theme overrides cannot disable domains (no false values) and do not support meta or scalePowers configuration.

Best Practices

  • Start with defaults: Use the preset as-is initially, then customize as needed
  • Override strategically: Only customize the domains that need to differ from defaults
  • Use the return value: Access the returned variables for use with ref() in your styles
  • Combine with themes: Use the themes option to define dark mode, compact, or brand theme overrides directly in the preset
  • Replace defaults explicitly: Partial overrides merge with defaults by default. Pass meta: { merge: false } to replace a domain's defaults entirely with your custom record

FAQ