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, a generator function, and an optional options object. The base name is used to generate the utility class names, while the generator function defines how the utility should be applied.

The function returns a utility creator that you can call with an object containing value mappings. Each key in the object corresponds to a utility class, and the value is the CSS declaration to apply.

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.

You're absolutely right! I should maintain consistency with the existing pattern. Here's the corrected version that adds modifier to the destructuring:

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.

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),
}, {
    modifiers: [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 }, {
    modifiers: [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),
}, {
    modifiers: [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),
}, {
    modifiers: [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