Design Tokens Presets
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
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;
:root {
/* Spacing */
--spacing: 1rem;
--spacing--2xs: 0.25rem;
--spacing--xs: 0.5rem;
--spacing--sm: 0.75rem;
--spacing--md: 1rem;
--spacing--lg: 1.5rem;
--spacing--xl: 2rem;
--spacing--2xl: 3rem;
--spacing--3xl: 4rem;
/* Colors (base + variations) */
--color--primary: oklch(0.62 0.21 255);
--color--primary-50: oklch(from var(--color--primary) 0.05 c h / a);
--color--primary-100: oklch(from var(--color--primary) 0.1 c h / a);
/* ... more color variations */
/* Typography */
--font-family--base: -apple-system, BlinkMacSystemFont, ...;
--font-size: 1rem;
--font-size--xs: 0.75rem;
/* ... more typography tokens */
/* And many more... */
}
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 entirelyRecord<string, TokenValue>: Use custom values
| Option | Type | Description |
|---|---|---|
spacing | false | Record<string, TokenValue> | Spacing tokens (padding, margin, gap) |
borderWidth | false | Record<string, TokenValue> | Border width tokens |
borderRadius | false | Record<string, TokenValue> | Border radius tokens |
borderStyle | false | Record<string, TokenValue> | Border style tokens |
boxShadow | false | Record<string, TokenValue> | Box shadow elevation tokens |
zIndex | false | Record<string, TokenValue> | Z-index stacking order tokens |
colors | false | Record<string, string> | Semantic color tokens |
meta.colors | ColorsMetaConfig | Color generation options |
fontFamily | false | Record<string, TokenValue> | Font family tokens |
fontSize | false | 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) |
fontStyle | false | Record<string, TokenValue> | Font style tokens |
fontWeight | false | Record<string, TokenValue> | Font weight tokens |
lineHeight | false | Record<string, TokenValue> | Line height tokens |
letterSpacing | false | Record<string, TokenValue> | Letter spacing tokens |
scale | false | Record<string, TokenValue> | Modular scale ratios (must include default key referencing scale for scalePowers) |
scalePowers | readonly number[] | Scale power levels |
breakpoint | false | Record<string, number> | Responsive breakpoints |
easing | false | Record<string, TokenValue> | Animation easing functions |
fluidViewport | false | true | { minWidth?, maxWidth? } | Fluid viewport range powering fluid.breakpoint (see Fluid Typography) |
fluidFontSize | false | true | Viewport-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) |
themes | Record<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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @border-radius.md | borderRadius | --border-radius |
none | 0 | borderRadiusNone | --border-radius--none |
sm | 0.125rem | borderRadiusSm | --border-radius--sm |
md | 0.25rem | borderRadiusMd | --border-radius--md |
lg | 0.5rem | borderRadiusLg | --border-radius--lg |
xl | 0.75rem | borderRadiusXl | --border-radius--xl |
2xl | 1rem | borderRadius2xl | --border-radius--2xl |
full | 9999px | borderRadiusFull | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @border-style.solid | borderStyle | --border-style |
none | none | borderStyleNone | --border-style--none |
solid | solid | borderStyleSolid | --border-style--solid |
dashed | dashed | borderStyleDashed | --border-style--dashed |
dotted | dotted | borderStyleDotted | --border-style--dotted |
double | double | borderStyleDouble | --border-style--double |
groove | groove | borderStyleGroove | --border-style--groove |
inset | inset | borderStyleInset | --border-style--inset |
outset | outset | borderStyleOutset | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @border-width.thin | borderWidth | --border-width |
none | 0 | borderWidthNone | --border-width--none |
thin | thin | borderWidthThin | --border-width--thin |
medium | medium | borderWidthMedium | --border-width--medium |
thick | thick | borderWidthThick | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @box-shadow.md | boxShadow | --box-shadow |
none | none | boxShadowNone | --box-shadow--none |
xs | Subtle card/surfaces shadow | boxShadowXs | --box-shadow--xs |
sm | Small elevation shadow | boxShadowSm | --box-shadow--sm |
md | Popover/raised button shadow | boxShadowMd | --box-shadow--md |
lg | Modal/floating panel shadow | boxShadowLg | --box-shadow--lg |
xl | Drawer/high elevation shadow | boxShadowXl | --box-shadow--xl |
2xl | Highest elevation/toast shadow | boxShadow2xl | --box-shadow--2xl |
inner | Inset shadow for wells | boxShadowInner | --box-shadow--inner |
ring | Focus ring shadow | boxShadowRing | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @z-index.base | zIndex | --z-index |
hide | -1 | zIndexHide | --z-index--hide |
base | 0 | zIndexBase | --z-index--base |
dropdown | 100 | zIndexDropdown | --z-index--dropdown |
sticky | 200 | zIndexSticky | --z-index--sticky |
overlay | 300 | zIndexOverlay | --z-index--overlay |
modal | 400 | zIndexModal | --z-index--modal |
popover | 500 | zIndexPopover | --z-index--popover |
toast | 600 | zIndexToast | --z-index--toast |
max | 9999 | zIndexMax | --z-index--max |
auto | auto | zIndexAuto | --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;
| Key | Value (px) | Variable | Output |
|---|---|---|---|
xs | 0 | breakpointXs | --breakpoint--xs |
sm | 576 | breakpointSm | --breakpoint--sm |
md | 768 | breakpointMd | --breakpoint--md |
lg | 992 | breakpointLg | --breakpoint--lg |
xl | 1200 | breakpointXl | --breakpoint--xl |
2xl | 1440 | breakpoint2xl | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
primary | #3b82f6 | colorPrimary | --color--primary |
secondary | #6b7280 | colorSecondary | --color--secondary |
success | #22c55e | colorSuccess | --color--success |
warning | #f59e0b | colorWarning | --color--warning |
error | #ef4444 | colorError | --color--error |
info | #06b6d4 | colorInfo | --color--info |
light | #f8fafc | colorLight | --color--light |
dark | #1e293b | colorDark | --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:
| Option | Type | Default | Description |
|---|---|---|---|
generateLevels | boolean | true | Generate levels (50-950) |
generateShades | boolean | true | Generate darker shades |
generateTints | boolean | true | Generate lighter tints |
levels | Record<string | number, number> | { 50: 5, 100: 10, ... } | Custom levels |
shadeLevels | Record<string | number, number> | { "shade-50": 5, "shade-100": 10, ... } | Custom shade levels |
tintLevels | Record<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:
| Key | Value | Variable | Output |
|---|---|---|---|
linear | linear | easingLinear | --easing--linear |
ease | ease | easingEase | --easing--ease |
ease-in | ease-in | easingEaseIn | --easing--ease-in |
ease-out | ease-out | easingEaseOut | --easing--ease-out |
ease-in-out | ease-in-out | easingEaseInOut | --easing--ease-in-out |
Sine:
| Key | Value | Variable | Output |
|---|---|---|---|
ease-in-sine | cubic-bezier(0.47, 0, 0.745, 0.715) | easingEaseInSine | --easing--ease-in-sine |
ease-out-sine | cubic-bezier(0.39, 0.575, 0.565, 1) | easingEaseOutSine | --easing--ease-out-sine |
ease-in-out-sine | cubic-bezier(0.445, 0.05, 0.55, 0.95) | easingEaseInOutSine | --easing--ease-in-out-sine |
Quad:
| Key | Value | Variable | Output |
|---|---|---|---|
ease-in-quad | cubic-bezier(0.55, 0.085, 0.68, 0.53) | easingEaseInQuad | --easing--ease-in-quad |
ease-out-quad | cubic-bezier(0.25, 0.46, 0.45, 0.94) | easingEaseOutQuad | --easing--ease-out-quad |
ease-in-out-quad | cubic-bezier(0.455, 0.03, 0.515, 0.955) | easingEaseInOutQuad | --easing--ease-in-out-quad |
Cubic:
| Key | Value | Variable | Output |
|---|---|---|---|
ease-in-cubic | cubic-bezier(0.55, 0.055, 0.675, 0.19) | easingEaseInCubic | --easing--ease-in-cubic |
ease-out-cubic | cubic-bezier(0.215, 0.61, 0.355, 1) | easingEaseOutCubic | --easing--ease-out-cubic |
ease-in-out-cubic | cubic-bezier(0.645, 0.045, 0.355, 1) | easingEaseInOutCubic | --easing--ease-in-out-cubic |
Quart:
| Key | Value | Variable | Output |
|---|---|---|---|
ease-in-quart | cubic-bezier(0.895, 0.03, 0.685, 0.22) | easingEaseInQuart | --easing--ease-in-quart |
ease-out-quart | cubic-bezier(0.165, 0.84, 0.44, 1) | easingEaseOutQuart | --easing--ease-out-quart |
ease-in-out-quart | cubic-bezier(0.77, 0, 0.175, 1) | easingEaseInOutQuart | --easing--ease-in-out-quart |
Quint:
| Key | Value | Variable | Output |
|---|---|---|---|
ease-in-quint | cubic-bezier(0.755, 0.05, 0.855, 0.06) | easingEaseInQuint | --easing--ease-in-quint |
ease-out-quint | cubic-bezier(0.23, 1, 0.32, 1) | easingEaseOutQuint | --easing--ease-out-quint |
ease-in-out-quint | cubic-bezier(0.86, 0, 0.07, 1) | easingEaseInOutQuint | --easing--ease-in-out-quint |
Expo:
| Key | Value | Variable | Output |
|---|---|---|---|
ease-in-expo | cubic-bezier(0.95, 0.05, 0.795, 0.035) | easingEaseInExpo | --easing--ease-in-expo |
ease-out-expo | cubic-bezier(0.19, 1, 0.22, 1) | easingEaseOutExpo | --easing--ease-out-expo |
ease-in-out-expo | cubic-bezier(1, 0, 0, 1) | easingEaseInOutExpo | --easing--ease-in-out-expo |
Circ:
| Key | Value | Variable | Output |
|---|---|---|---|
ease-in-circ | cubic-bezier(0.6, 0.04, 0.98, 0.335) | easingEaseInCirc | --easing--ease-in-circ |
ease-out-circ | cubic-bezier(0.075, 0.82, 0.165, 1) | easingEaseOutCirc | --easing--ease-out-circ |
ease-in-out-circ | cubic-bezier(0.785, 0.135, 0.15, 0.86) | easingEaseInOutCirc | --easing--ease-in-out-circ |
Back (with overshoot):
| Key | Value | Variable | Output |
|---|---|---|---|
ease-in-back | cubic-bezier(0.6, -0.28, 0.735, 0.045) | easingEaseInBack | --easing--ease-in-back |
ease-out-back | cubic-bezier(0.175, 0.885, 0.32, 1.275) | easingEaseOutBack | --easing--ease-out-back |
ease-in-out-back | cubic-bezier(0.68, -0.55, 0.265, 1.55) | easingEaseInOutBack | --easing--ease-in-out-back |
Special (linear() functions):
| Key | Description | Variable | Output |
|---|---|---|---|
spring | Natural spring animation | easingSpring | --easing--spring |
bounce | Bouncy animation effect | easingBounce | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @font-family.base | fontFamily | --font-family |
base | System font stack (sans-serif) | fontFamilyBase | --font-family--base |
print | Georgia, Times New Roman (serif) | fontFamilyPrint | --font-family--print |
mono | SFMono-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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @font-size.md | fontSize | --font-size |
xs | 0.75rem | fontSizeXs | --font-size--xs |
sm | 0.875rem | fontSizeSm | --font-size--sm |
md | 1rem | fontSizeMd | --font-size--md |
lg | 1.125rem | fontSizeLg | --font-size--lg |
xl | 1.25rem | fontSizeXl | --font-size--xl |
2xl | 1.5rem | fontSize2xl | --font-size--2xl |
3xl | 1.875rem | fontSize3xl | --font-size--3xl |
4xl | 2.25rem | fontSize4xl | --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.
| Key | Default | Variable | Output |
|---|---|---|---|
minWidth | 320 | fluidMinWidth | --fluid--min-width |
maxWidth | 1440 | fluidMaxWidth | --fluid--max-width |
| (constant) | 100vw | fluidScreen | --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.
| Key | Default | Variable | Output |
|---|---|---|---|
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] }).
| Key | Step | Value (default) | Variable | Output |
|---|---|---|---|---|
min | — | 16 (configurable fluid base) | fontSizeMin | --font-size--min |
max | — | 18 (configurable fluid base) | fontSizeMax | --font-size--max |
default | — | @font-size.md | fontSize | --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 |
md | 0 | [@font-size.min * @scale.min-powers.0, @font-size.max * @scale.max-powers.0] | fontSizeMd | --font-size--md |
lg | 1 | [@font-size.min * @scale.min-powers.1, @font-size.max * @scale.max-powers.1] | fontSizeLg | --font-size--lg |
xl | 2 | [@font-size.min * @scale.min-powers.2, @font-size.max * @scale.max-powers.2] | fontSizeXl | --font-size--xl |
2xl | 3 | [@font-size.min * @scale.min-powers.3, @font-size.max * @scale.max-powers.3] | fontSize2xl | --font-size--2xl |
3xl | 4 | [@font-size.min * @scale.min-powers.4, @font-size.max * @scale.max-powers.4] | fontSize3xl | --font-size--3xl |
4xl | 5 | [@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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @font-style.normal | fontStyle | --font-style |
italic | italic | fontStyleItalic | --font-style--italic |
oblique | oblique | fontStyleOblique | --font-style--oblique |
normal | normal | fontStyleNormal | --font-style--normal |
inherit | inherit | fontStyleInherit | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @font-weight.normal | fontWeight | --font-weight |
extralight | 200 | fontWeightExtralight | --font-weight--extralight |
light | 300 | fontWeightLight | --font-weight--light |
normal | normal | fontWeightNormal | --font-weight--normal |
medium | 500 | fontWeightMedium | --font-weight--medium |
semibold | 600 | fontWeightSemibold | --font-weight--semibold |
bold | bold | fontWeightBold | --font-weight--bold |
black | 900 | fontWeightBlack | --font-weight--black |
lighter | lighter | fontWeightLighter | --font-weight--lighter |
bolder | bolder | fontWeightBolder | --font-weight--bolder |
inherit | inherit | fontWeightInherit | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @letter-spacing.normal | letterSpacing | --letter-spacing |
tighter | -0.05em | letterSpacingTighter | --letter-spacing--tighter |
tight | -0.025em | letterSpacingTight | --letter-spacing--tight |
normal | normal | letterSpacingNormal | --letter-spacing--normal |
wide | 0.05em | letterSpacingWide | --letter-spacing--wide |
wider | 0.1em | letterSpacingWider | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @line-height.normal | lineHeight | --line-height |
tight | 1.2 | lineHeightTight | --line-height--tight |
snug | 1.35 | lineHeightSnug | --line-height--snug |
normal | 1.5 | lineHeightNormal | --line-height--normal |
relaxed | 1.65 | lineHeightRelaxed | --line-height--relaxed |
loose | 1.9 | lineHeightLoose | --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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @scale.minor-third | scale | --scale |
minor-second | 1.067 | scaleMinorSecond | --scale--minor-second |
major-second | 1.125 | scaleMajorSecond | --scale--major-second |
minor-third | 1.2 | scaleMinorThird | --scale--minor-third |
major-third | 1.25 | scaleMajorThird | --scale--major-third |
perfect-fourth | 1.333 | scalePerfectFourth | --scale--perfect-fourth |
augmented-fourth | 1.414 | scaleAugmentedFourth | --scale--augmented-fourth |
perfect-fifth | 1.5 | scalePerfectFifth | --scale--perfect-fifth |
golden | 1.618 | scaleGolden | --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 }
| Power | Formula | Output |
|---|---|---|
-2 | 1 / scale / scale | --scale-power---2 |
-1 | 1 / scale | --scale-power---1 |
0 | 1 | --scale-power--0 |
1 | scale | --scale-power--1 |
2 | scale * scale | --scale-power--2 |
3 | scale * scale * scale | --scale-power--3 |
4 | scale * scale * scale * scale | --scale-power--4 |
5 | scale * 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;
| Key | Value | Variable | Output |
|---|---|---|---|
default | @spacing.md | spacing | --spacing |
2xs | 0.25rem | spacing2xs | --spacing--2xs |
xs | 0.5rem | spacingXs | --spacing--xs |
sm | 0.75rem | spacingSm | --spacing--sm |
md | 1rem | spacingMd | --spacing--md |
lg | 1.5rem | spacingLg | --spacing--lg |
xl | 2rem | spacingXl | --spacing--xl |
2xl | 3rem | spacing2xl | --spacing--2xl |
3xl | 4rem | spacing3xl | --spacing--3xl |
Examples
Full Customization
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
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.
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;
import { styleframe } from 'styleframe';
import { useDesignTokensPreset } from '@styleframe/theme';
const s = styleframe();
const preset = useDesignTokensPreset(s, {
// Tailor the viewport range to your target devices.
fluidViewport: { minWidth: 375, maxWidth: 1920 },
// Choose modular-scale ratios for harmonious, Utopia-style proportions.
// The default uses major-second (1.125) on the min viewport and
// major-third (1.25) on the max — change either independently.
fluidScale: { min: '@scale.minor-third', max: '@scale.perfect-fourth' },
// Override individual steps with literal pixel ranges via `fontSize`.
// Each tuple [min, max] generates a calc() fluid expression.
fontSize: { md: [16, 18], lg: [18, 22] },
});
export default s;
import { styleframe } from 'styleframe';
import { useDesignTokensPreset } from '@styleframe/theme';
import { useFluidClamp } from '@styleframe/theme';
const s = styleframe();
// Opt out of the global fluid scale and make individual keys fluid by passing
// `useFluidClamp(...)` inline. This is the recommended way to mix static and
// fluid values without hitting the namespace collision that the default
// fluid scale solves by replacing the whole domain.
const preset = useDesignTokensPreset(s, {
fluidFontSize: false, // disable fluid; static `fontSize` runs
fluidViewport: true, // keep fluid.* vars so useFluidClamp works
fontSize: {
default: '@font-size.md',
sm: '0.875rem',
md: useFluidClamp(s, [16, 18]),
lg: useFluidClamp(s, [18, 22]),
xl: '1.5rem',
},
});
export default s;
import { styleframe } from 'styleframe';
import { useDesignTokensPreset } from '@styleframe/theme';
const s = styleframe();
// Pass `fluidFontSize: false` to fall back to the static `fontSize` domain.
// Use this when you want fixed `rem` values at every breakpoint.
const preset = useDesignTokensPreset(s, {
fluidFontSize: false,
});
export default s;
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
| Export | Description |
|---|---|
defaultSpacingValues | Spacing scale values |
defaultBorderWidthValues | Border width values |
defaultBorderRadiusValues | Border radius values |
defaultBorderStyleValues | Border style values |
defaultBoxShadowValues | Box shadow elevation values |
defaultColorValues | Semantic color values |
colorLevelValues | Level values |
defaultColorShadeValues | Shade level values |
defaultColorTintValues | Tint level values |
defaultFontFamilyValues | Font family values |
defaultFontSizeValues | Font size scale values |
defaultFontStyleValues | Font style values |
defaultFontWeightValues | Font weight values |
defaultLineHeightValues | Line height values |
defaultLetterSpacingValues | Letter spacing values |
defaultScaleValues | Modular scale ratio values |
defaultScalePowerValues | Scale power levels |
defaultBreakpointValues | Responsive breakpoint values |
defaultEasingValues | Animation easing function values |
defaultColorsMetaConfig | Default 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
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;
:root {
--color--primary: #007bff;
--color--secondary: #6c757d;
/* ... other tokens */
}
[data-theme="dark"] {
--color--primary: #60a5fa;
--color--secondary: #cbd5e1;
}
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:
| Domain | Type |
|---|---|
spacing | Record<string, TokenValue> |
borderWidth | Record<string, TokenValue> |
borderRadius | Record<string, TokenValue> |
borderStyle | Record<string, TokenValue> |
boxShadow | Record<string, TokenValue> |
colors | Record<string, string> |
fontFamily | Record<string, TokenValue> |
fontSize | Record<string, TokenValue> |
fontStyle | Record<string, TokenValue> |
fontWeight | Record<string, TokenValue> |
lineHeight | Record<string, TokenValue> |
letterSpacing | Record<string, TokenValue> |
scale | Record<string, TokenValue> |
breakpoint | Record<string, number> |
easing | Record<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
themesoption 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
useColorDesignTokens() or useSpacingDesignTokens() for additional custom tokens.Color variations follow a consistent naming pattern:
const {
colorPrimary,
colorPrimary500,
colorPrimaryShade100,
colorPrimaryTint100,
} = preset;
- Base color:
colorPrimary - Level:
colorPrimary500(for 50% lightness) - Shade:
colorPrimaryShade100 - Tint:
colorPrimaryTint100
The preset provides:
- Consistent, well-tested default values
- Automatic color variation generation
- Less boilerplate code
- Easy customization through a single config object
Yes! After calling the preset, you can use any composable to add more tokens:
const preset = useDesignTokensPreset(s);
const { colorPrimary } = preset;
// Add custom tokens
const { colorBrand } = useColorDesignTokens(s, { brand: '#ff00ff' });
Use fluid (the default) when you want type to scale smoothly with the viewport so a single value reads well on both mobile and desktop without media queries. This is the Utopia approach.
Use static (fluidFontSize: false) when you want font sizes to stay constant within a breakpoint and only change at media-query boundaries — predictable and easy to reason about.
Use the hybrid pattern (fluidFontSize: false + fluidViewport: true + useFluidClamp inline on specific keys) when only a few values — typically display headings — need to scale fluidly. See the Customizing Fluid Typography example.
Don't try to enable both fontSize and the default fluid scale at once: they target the same font-size.* namespace, so the preset silently ignores the static config when fluid is on.
Just pass the custom values — they merge with defaults out of the box:
const preset = useDesignTokensPreset(s, {
// Custom values are added to defaults
spacing: { '4xl': '6rem', '5xl': '8rem' },
colors: { brand: '#ff6600' },
});
// All default spacing values plus '4xl' and '5xl'
// All default colors plus 'brand'
If you instead want a domain's defaults to be replaced entirely by your custom record, opt out via meta: { merge: false }:
const preset = useDesignTokensPreset(s, {
meta: { merge: false },
// Only the keys you list exist
spacing: { sm: '0.25rem', md: '0.5rem', lg: '1rem' },
});
Overview
Explore Styleframe's comprehensive design token system. Create consistent, scalable design systems with composable functions for colors, typography, spacing, and more.
Border Radiuses
Create and manage border radius design tokens with CSS variables for consistent rounded corners and curved edges across your application.