Style Grouping

NEW
Group multiple CSS properties under a single prop, each with its own value. One prop, one class name, multiple declarations.
The concept
JSX
// By default, a styleName array applies the SAME value to all CSS properties:
{
  styleName: ['padding-left', 'padding-right'],
  values: [2, 4, 6] as const,
  valueFormat: (value) => `${value / 4}rem`,
}
// px={4} → padding-left: 1rem; padding-right: 1rem  (same value)

// With per-property valueFormat, each CSS property gets a DIFFERENT value.
// The 3rd argument to valueFormat is the current styleName being generated:
{
  styleName: ['font-size', 'font-weight', 'line-height', 'letter-spacing'],
  values: ['display-lg'] as const,
  valueFormat: (value, getVariable, styleName) => {
    // styleName is 'font-size', then 'font-weight', then 'line-height', etc.
    // Return a different value for each one.
  },
}
Generated CSS
CSS
/* <Box textStyle="display-lg" />
   Generates a single class with four different CSS declarations: */

.textStyle-display-lg {
  font-size: var(--text-display-lg-size);            /* 36px */
  font-weight: var(--text-display-lg-weight);        /* 700 */
  line-height: var(--text-display-lg-line-height);   /* 1.2 */
  letter-spacing: var(--text-display-lg-letter-spacing); /* -0.02em */
}
Full example: typography presets
JSX
// 1. Define CSS variables for each property per variant
Box.extend(
  {
    'text-display-lg-size': '36px',
    'text-display-lg-weight': '700',
    'text-display-lg-line-height': '1.2',
    'text-display-lg-letter-spacing': '-0.02em',

    'text-display-sm-size': '28px',
    'text-display-sm-weight': '700',
    'text-display-sm-line-height': '1.25',
    'text-display-sm-letter-spacing': '-0.015em',
  },
  // 2. Create a prop with styleName array + per-property valueFormat
  {
    textStyle: [
      {
        values: ['display-lg', 'display-sm'] as const,
        styleName: ['font-size', 'font-weight', 'line-height', 'letter-spacing'],
        // styleName is the property being generated, so it is optional in the signature —
        // it is only passed for a multi-property prop like this one.
        valueFormat: (value: string, getVariable: (name: string) => string, styleName?: string) => {
          const suffixMap: Record<string, string> = {
            'font-size': 'size',
            'font-weight': 'weight',
            'line-height': 'line-height',
            'letter-spacing': 'letter-spacing',
          };
          return getVariable(`text-${value}-${suffixMap[styleName!]}`);
        },
      },
    ],
  },
  {},
);
Live: display-lg
The quick brown fox jumps over the lazy dog
JSX
<Box
  textStyle="display-lg"
  theme={{ dark: { color: 'white' }, light: { color: 'slate-900' } }}
>
  The quick brown fox jumps over the lazy dog
</Box>
Live: display-sm
The quick brown fox jumps over the lazy dog
JSX
<Box
  textStyle="display-sm"
  theme={{ dark: { color: 'white' }, light: { color: 'slate-900' } }}
>
  The quick brown fox jumps over the lazy dog
</Box>
Composing with other Box props
Display Large in color
Display Small muted
Regular body text for comparison — using individual fontSize and lineHeight props. The textStyle prop above sets four CSS properties at once from a single value.
JSX
<Flex d="column" gap={6}>
  <Box textStyle="display-lg" color="indigo-500">Display Large in color</Box>
  <Box textStyle="display-sm" color="slate-500">Display Small muted</Box>
  <Box
    fontSize={16}
    lineHeight={28}
    theme={{ dark: { color: 'slate-400' }, light: { color: 'slate-600' } }}
  >
    Regular body text for comparison — using individual fontSize and lineHeight props. The textStyle prop above sets four CSS properties at once from a single value.
  </Box>
</Flex>