
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
theme-system
Advanced tools
Theme system is a libary that combines the benefits of utility class libraries like [https://tailwindcss.com/](https://tailwindcss.com/) with the DX of css-in-js libraries like Styled Components or Emotion combined with styled-system.
Theme system is a libary that combines the benefits of utility class libraries like https://tailwindcss.com/ with the DX of css-in-js libraries like Styled Components or Emotion combined with styled-system.
At Reversed we make heavy use of both styled-components and styled-system. It offers a great DX but comes at a cost, since each Box component and styled.div call adds bytes to the JS bundle and these styles are inserted during runtime. We've looked for alternatives and found Linaria which looks great. It's mainly the same API as styled-components, but extracts styles to static css. On the other hand we've looked at https://tailwindcss.com/, which is gaining a lot of attention and rightfully so.
We didn't want to lose our Box component though and wanted the freedom of our own design system. So we've build Theme System. Theme-System combines best of both worlds; it creates a fixed set of utility-clases for maximum reusability with the DX of styled-system props.
Run yarn add theme-system@latest
For a working example with next.js & linaria, please check the examples folder.
Create a theme system config file, for example theme-system.ts, inside this file, create the utility classes and parser using the createThemeSystem function. The createThemeSystem function accepts a single theme object and return an object with three properties.
Your theme object should look like this:
type Theme = {
breakpoints: { [key: string]: string | number }
fontWeights: { [key: string]: string | number }
fontFamilies: { [key: string]: string | number }
space: { [key: string]: string | number }
colors: { [key: string]: string | number }
}
Example:
// theme-system.ts
const theme = {
breakpoints: {
md: '1024px',
},
fontWeights: {
regular: '400',
},
fontSizes: {
large: '3rem',
regular: '1rem',
},
fontFamilies: {
heading: 'serif',
body: 'sans-serif',
},
space: {
'0': 0,
'1': '1rem',
'2': '2rem',
},
colors: {
primary: '#236FEA',
info: '#258AE7',
success: '#27C62D',
},
}
export type Theme = typeof theme
export const { utilities, parse, parseAll } = createThemeSystem<Theme>(theme)
Note the
export type Theme = typeof themeline, this is needed to have typechecking on your theme object.
The utilities property is a string containing the css with the utility classes, you should add this once inside your global css.
The parse & parseAll functions are identical in implementation, but parse is strictly typed based on your theme.
The parse function allows you to generate a string of classnames based on your theme which you can use anywhere in your code. Each property can be one of the values of that property in your theme (e.g. color: 'primary') or an object with one of your breakpoint keys as the key, or _ for the initial style. For example:
<p
className={parse({
color: 'primary',
fontSize: 'large',
fontFamily: {
_: 'body',
md: 'heading',
},
})}
>
Using parse
</p>
Renders this HTML:
<p class="font-family-body md-font-family-heading font-size-large color-primary">Using parse</p>
The parse function is strictly typed, so passing in invalid properties will result in a typescript.
The parseAll function allows you to pass in a props object without strict type checking. This allows you to build custom components with typechecking on their props and passing a complete props object to parseAll, generating the right class names. A Box component example:
import React, { FC, HTMLAttributes } from 'react'
import { ThemeSystemProps, filterProps } from 'theme-system'
import { Theme, parseAll } from '../lib/theme-system'
import { cx } from 'linaria'
type Props = HTMLAttributes<HTMLDivElement> & ThemeSystemProps<Theme> & {}
const Box = React.forwardRef<HTMLDivElement, Props>(({ className, children, ...props }, ref) => {
return (
<div className={cx(className, parseAll(props))} ref={ref} {...filterProps(props)}>
{children}
</div>
)
})
export default Box
In this example, the filterProps helper removes all theme system related props from the object, preventing your div having html attributes like color or height in the DOM.
Using the Box component, a component that looks like this:
<Box color="primary" fontSize="large" fontFamily={{ _: 'body', md: 'heading' }}>
Using a Box component
</Box>
Will render output like this:
<div class="font-family-body md-font-family-heading font-size-large color-primary">Using parse</div>
Both parse & parseAll support passing an additional classname or as the second argument. For example: parse({color:primary}, 'additional-class') will output color-primary additional-class.
Important: the classnames are hashed in production, don't use them directly.
This needs a little more documentation work but these props are enabled:
| Prop | Value |
|---|---|
| mt | theme.space |
| mr | theme.space |
| mb | theme.space |
| ml | theme.space |
| mx | theme.space |
| my | theme.space |
| m | theme.space |
| pt | theme.space |
| pr | theme.space |
| pb | theme.space |
| pl | theme.space |
| px | theme.space |
| py | theme.space |
| p | theme.space |
| Prop | Value |
|---|---|
| display | 'inline', 'block', 'flex', 'grid', 'inline-block', 'none', 'initial' |
| width | '100%' , 'auto' , 'screen' |
| minWidth | '100%' , 'auto' , 'screen' |
| height | '100%' , 'auto' , 'screen' |
| minHeight | '100%' , 'auto' , 'screen' |
| Prop | Value |
|---|---|
| fontFamily | theme.fontFamilies |
| fontWeight | theme.fontWeights |
| fontSize | theme.fontSizes |
| color | theme.colors |
| textAlign | 'left', 'center', 'right' |
| Prop | Value |
|---|---|
| bg | theme.colors |
| Prop | Value |
|---|---|
| alignItems | 'center', 'flex-start', 'flex-end' |
| justifyContent | 'center', 'flex-start', 'flex-end', 'space-between', 'space-around' |
| flexWrap | 'wrap' ,'wrap-reverse' |
Note that this is expiremtal but ideas and pr's are welcome. Theme System is based on TSDX, check that out if you'd like to contribute.
FAQs
Theme system is a libary that combines the benefits of utility class libraries like [https://tailwindcss.com/](https://tailwindcss.com/) with the DX of css-in-js libraries like Styled Components or Emotion combined with styled-system.
We found that theme-system demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.