What is xstyled?
mainstyled-system and the utility-first approach of Tailwind CSS, but within the CSS-in-JS ecosystem.repository·main·Indexed 25 days ago
https://github.com/styled-components/xstyledA utility-first CSS-in-JS framework built for React that enables interfaces using shorthand props and responsive design tokens. It provides a utility-first API via the x object, support for styled-components and Emotion, and a comprehensive system for managing theme breakpoints, color modes, and CSS custom properties.
styled-system and the utility-first approach of Tailwind CSS, but within the CSS-in-JS ecosystem.PropTypes based on the style props defined in @xstyled/system. This allows you to enforce type safety for the design system props (like colors, spacing, and typography) used in your components.xstyled is designed to be highly performant and includes a comprehensive set of utilities for building design systems.
The package size is approximately ~15kb gzipped, which includes all utilities and dependencies. This is intended to provide a complete toolkit for a website or design system out of the box.
@xstyled/styled-components: ~15.4kb gzipped@xstyled/emotion: ~15.7kb gzippedstyled-components.sizes theme section, append a suffix s to the value. This distinguishes theme scale values from fluid percentage values (which use numbers between 0 and 1). For example, if your theme has a size 0.5, you access it using 0.5s.If you do not provide a durations section in your theme, xstyled uses a default set of durations based on Google Material Design recommendations.
const defaultTheme = {
// ...
durations: {
instant: '100ms',
'fast-in': '250ms',
'fast-out': '200ms',
'slow-in': '300ms',
'slow-out': '250ms',
},
}You can conditionally apply transitions based on user accessibility preferences using motionSafe and motionReduce states within the transition object.
For example, you can enable transitions by default but disable them if the user has requested reduced motion via motionReduce: 'none'.
<x.button
color={{ hover: 'red' }}
transition={{ _: true, motionReduce: 'none' }}
>
Hover me
</x.button>Benchmarks comparing @xstyled/system to styled-system show that while styled-system may have a higher operations-per-second count, xstyled provides additional features that account for the difference:
styled-system does not.@xstyled/system x 431,828 ops/sec ±1.06% (86 runs sampled)
styled-system x 549,224 ops/sec ±0.85% (90 runs sampled)
Fastest is styled-systemIn v3, states are specified using object syntax, similar to how breakpoints are handled. States can be nested within breakpoints or other states.
States are configurable in the theme under the states key:
export const theme = {
states: {
hover: '&:hover',
// ...
},
}// Basic state usage
<x.button color={{ _: 'red-500', hover: 'red-300' }} />
// Mixed screens and states
<x.button color={{ _: 'red-600', md: { _: 'red-500', hover: 'red-300' } }} />
// Nested states
<x.div bg={{ first: { odd: 'blue' } } } />When using a function in the css prop with @xstyled/emotion, the signature and usage differ from standard Emotion:
{ theme }.css function call.With xstyled:
import { jsx } from '@xstyled/emotion'
const Button = ({ children }) => {
return (
<button
css={({ theme }) =>
css({
paddingTop: theme.space[1],
})
}
>
{children}
</button>
)
}/** @jsx jsx */
import { jsx } from '@xstyled/emotion'
const Button = ({ children }) => {
return (
<button
css={({ theme }) =>
css({
paddingTop: theme.space[1],
})
}
>
{children}
</button>
)
}xstyled automatically applies values defined in your theme.sizes section.
Important Note on Scales: Because values between 0 and 1 are reserved for fluid/percentage calculations, you must append a suffix s to target specific scale values from your theme. For example, a theme value of 0.5 must be referenced as 0.5s and 1 as 1s to avoid being treated as a percentage.
Example of using theme scales vs raw numbers:
<x.div maxHeight="1s" /> {/* Targets theme scale value 1 */}
<x.div maxHeight={8} /> {/* Sets fixed 8px */}<x.div
maxHeight="1s"
h={32}
/>When your elements are in reverse order (for example, using flexDirection="row-reverse" or flexDirection="column-reverse"), the standard divide utilities might apply borders to the wrong side. Use divideXReverse or divideYReverse to correct the border placement.
| React prop | CSS Property |
|---|---|
divideXReverse | --x-divide-x-reverse: 1; |
divideYReverse | --x-divide-y-reverse: 1; |
<x.div
display="flex"
flexDirection="column-reverse"
divideY
divideYReverse
divideColor="rose-500"
>
<x.div>1</x.div>
<x.div>2</x.div>
<x.div>3</x.div>
</x.div><x.div
display="flex"
flexDirection="column-reverse"
divideY
divideYReverse
divideColor="rose-500"
>
<x.div
textAlign="center"
fontWeight="extrabold"
fontSize="2xl"
color="rose-600"
py={3}
>
1
</x.div>
<x.div
textAlign="center"
fontWeight="extrabold"
fontSize="2xl"
color="rose-600"
py={3}
>
2
</x.div>
<x.div
textAlign="center"
fontWeight="extrabold"
fontSize="2xl"
color="rose-600"
py={3}
>
3
</x.div>
</x.div>Values defined in the sizes section of your theme are automatically available. To avoid conflicts with fluid range values (0 to 1), you must append a suffix s to target theme values. For example, a theme value of 0.5 is accessed via 0.5s and 1 is accessed via 1s.
<x.div w="1s" />
<x.div w={8} />
<x.div w={12} />