API Essentials

Utilities

Styleframe utilities provide reusable, single-purpose CSS classes with full type safety and recipe support. Build consistent, maintainable styling systems with atomic design patterns.

Overview

Utilities in Styleframe are reusable, single-purpose CSS classes that provide a foundation for atomic design patterns. They offer full type safety, auto-complete, and seamless integration with recipes to create flexible, maintainable styling systems that scale with your project.

Why use utilities?

Utilities help you:

  • Build atomic design patterns: Create small, focused CSS classes that do one thing well and can be composed together.
  • Maintain consistency: Ensure uniform spacing, colors, and typography across your entire application.
  • Enable rapid prototyping: Quickly build interfaces by combining pre-defined utility classes.
  • Integrate with recipes: Seamlessly work with responsive, state, and custom variants for maximum flexibility.

Defining Utilities

You define utilities using the utility() function from your styleframe instance:

import { styleframe } from "styleframe";

const s = styleframe();
const { variable, ref, utility } = s;

const spacing = variable("spacing", "1rem");
const spacingSm = variable("spacing--sm", "0.75rem");
const spacingMd = variable("spacing--md", ref(spacing));
const spacingLg = variable("spacing--lg", "1.25rem");

const createMarginUtility = utility("margin", ({ value }) => ({
    margin: value,
}));

createMarginUtility({
    default: ref(spacing),
    sm: ref(spacingSm),
    md: ref(spacingMd),
    lg: ref(spacingLg),
});

export default s;

The utility() function takes a base name and a factory function. The base name is used to generate the utility class names, while the factory function defines how the utility should be applied.

The factory function receives a context object that includes:

  • value: The current value being processed from the entries object
  • Other declaration context helpers such as selector, variable, ref, media, etc.

The function returns a utility creator that you can call with an object containing value mappings (required), and an optional array of modifiers.

Each key in the entries object corresponds to a utility class, and the value is passed to the factory function.

Good to know: You can write utility names using kebab-case, camelCase, or PascalCase. When generating the utility classes, Styleframe will automatically convert them to kebab-case for consistency.

The default generated utility class format is _property-name:value, which is intuitive and CSS-like. You can customize this format in your styleframe configuration if needed.

Pro tip: Use descriptive utility names that clearly indicate their purpose. The CSS-like syntax makes utilities intuitive and easy to understand.

Defining Modifiers

Modifiers are functions that transform utility declarations to create variations based on conditions like hover states, media queries, or theme variations. They allow you to generate multiple related utility classes from a single base utility definition, extending your utilities with powerful conditional styling.

Modifiers are passed as the second parameter to the utility creator function:

import { styleframe } from "styleframe";

const s = styleframe();
const { utility, variable, ref, modifier } = s;

const colorPrimary = variable("color-primary", "#007bff");

const hover = modifier("hover", ({ declarations }) => ({
    [`&:hover`]: declarations,
}));

const createBackgroundUtility = utility("background", ({ value }) => ({
    background: value,
}));

createBackgroundUtility(
    {
        primary: ref(colorPrimary),
    },
    [hover],
);

export default s;

Complex Modifiers

Modifiers can contain complex logic to handle various conditions. The modifier function receives a context object with:

  • declarations: The CSS declarations generated by the utility factory function.
  • variables: An array containing variables defined in the utility factory function.
  • children: An array of child selectors generated by the utility factory function.
  • Other declaration context helpers such as selector, variable, ref, media, etc.
import { styleframe } from "styleframe";

const s = styleframe();
const { utility, variable, ref, modifier } = s;

const colorPrimary = variable("color-primary", "#007bff");

const hover = modifier(
    "hover",
    ({ declarations, variables, children, selector }) => {
        selector("&:hover", { declarations, variables, children });
    },
);

const createBackgroundUtility = utility("background", ({ value }) => ({
    background: value,
}));

createBackgroundUtility(
    {
        primary: ref(colorPrimary),
    },
    [hover],
);

export default s;

Multi-key Modifiers

You can create modifiers that apply one of multiple keys, useful such as responsive breakpoints or custom conditions:

import { styleframe, valueOf } from "styleframe";
import { useBreakpoints } from "@styleframe/theme";

const s = styleframe();
const { utility, variable, ref, modifier } = s;

const { breakpointSm, breakpointMd, breakpointLg } = useBreakpoints(s);

const breakpoints = {
    sm: valueOf(breakpointSm),
    md: valueOf(breakpointMd),
    lg: valueOf(breakpointLg),
};

const breakpointsMax = modifier(
    ["max-sm", "max-md", "max-lg"],
    ({ key, declarations }) => ({
        [`@media screen and (max-width: ${
            breakpoints[key.replace("max-", "")]
        })`]: declarations,
    }),
);

const createHiddenUtility = utility("hidden", () => ({
    display: "none",
}));

createHiddenUtility({ default: undefined }, [breakpointsMax]);

export default s;
Pro tip: Multi-key modifiers are great to create contextual utilities that adapt to different mutually-exclusive conditions, such as responsive breakpoints or theme variations.

Examples

Layout Utilities

Build flexible layout systems with display and positioning utilities:

import { styleframe } from "styleframe";

const s = styleframe();
const { utility } = s;

const createDisplayUtility = utility("display", ({ value }) => ({
    display: value,
}));

createDisplayUtility({
    block: "block",
    "inline-block": "inline-block",
    inline: "inline",
    flex: "flex",
    "inline-flex": "inline-flex",
    grid: "grid",
    none: "none",
});

const createFlexDirectionUtility = utility("flex-direction", ({ value }) => ({
    flexDirection: value,
}));

createFlexDirectionUtility({
    row: "row",
    column: "column",
});

const createJustifyContentUtility = utility("justify-content", ({ value }) => ({
    justifyContent: value,
}));

createJustifyContentUtility({
    start: "flex-start",
    center: "center",
    end: "flex-end",
    between: "space-between",
});

const createAlignItemsUtility = utility("align-items", ({ value }) => ({
    alignItems: value,
}));

createAlignItemsUtility({
    start: "flex-start",
    center: "center",
    end: "flex-end",
    stretch: "stretch",
});

export default s;

Complex Utilities

Create sophisticated utility systems that handle complex CSS properties and calculations:

import { styleframe, css } from "styleframe";

const s = styleframe();
const { variable, ref, utility } = s;

const createGridColumnUtility = utility("grid-column", ({ value }) => ({
    gridColumn: css`span ${value} / span ${value}`,
}));

const gridSpanMap = {};
for (let i = 1; i <= 12; i++) {
    gridSpanMap[i] = i;
}

createGridColumnUtility(gridSpanMap);

export default s;

Media Query Modifiers

You can create modifiers for responsive design using media queries:

import { styleframe } from "styleframe";

const s = styleframe();
const { utility, variable, ref, modifier } = s;

const colorPrimary = variable("color-primary", "#007bff");
const colorSecondary = variable("color-secondary", "#6c757d");

// Media query modifier for dark mode
const dark = modifier("dark", ({ declarations }) => ({
    ["@media (prefers-color-scheme: dark)"]: declarations,
}));

const createBackgroundUtility = utility("background", ({ value }) => ({
    background: value,
}));

createBackgroundUtility(
    {
        primary: ref(colorPrimary),
        secondary: ref(colorSecondary),
    },
    [dark],
);

export default s;

Combining Multiple Modifiers

Modifiers can be combined to create complex utility variations that handle multiple conditions:

import { styleframe } from "styleframe";

const s = styleframe();
const { utility, variable, ref, modifier } = s;

const colorPrimary = variable("color-primary", "#007bff");
const colorSecondary = variable("color-secondary", "#6c757d");

// Define multiple modifiers
const hover = modifier("hover", (declarations) => ({
    [`&:hover`]: declarations,
}));

const dark = modifier("dark", (declarations) => ({
    ["@media (prefers-color-scheme: dark)"]: declarations,
}));

const focus = modifier("focus", (declarations) => ({
    [`&:focus`]: declarations,
}));

const createBackgroundUtility = utility("background", ({ value }) => ({
    background: value,
}));

// Apply multiple modifiers to the same utility
createBackgroundUtility(
    {
        primary: ref(colorPrimary),
        secondary: ref(colorSecondary),
    },
    [hover, dark, focus],
);

export default s;
Good to know: When multiple modifiers are combined, Styleframe automatically generates all possible combinations in alphabetical order, giving you fine-grained control over when styles are applied.

Best Practices

  • Keep utilities focused: Each utility should have a single, clear responsibility and do one thing well.
  • Use descriptive naming: The _property:value format makes utilities intuitive and CSS-like to use.
  • Leverage variables: Build utilities on top of your design system variables for consistency and maintainability.
  • Create reusable modifiers: Define common modifiers (hover, focus, dark mode) once and reuse them across multiple utilities.
  • Plan modifier combinations: Consider which modifiers work well together and design your utilities to handle common combinations.
  • Use multi-key modifiers for mutually exclusive states: Breakpoints, themes, and directional variants benefit from multi-key modifier patterns.
  • Create composables: Group related utilities and their modifiers into composable functions for better organization and reusability.
  • Integrate with variants: Design utilities to work seamlessly with responsive, state, and custom variants.
  • Batch utility creation: Use object mapping to create multiple related utilities efficiently.
  • Test modifier combinations: Ensure that complex modifier combinations produce the expected CSS output.
  • Document modifier behavior: Clear documentation helps team members understand when and how to use specific modifier combinations.

FAQ