React components are more stylish with Trousers!
Trousers is a CSS-in-JS library designed to help developers author React apps with performant and semantic CSS. Trousers encourages semantic organization of styles without inadvertently increasing the runtime implications often associated with CSS-in-JS libraries.
Basic usage: yarn add trousers
or npm install trousers
Recommended for performance: yarn add @trousers/macro
or npm install @trousers/macro
- Lightweight
- Zero-config SSR
- Composable
- Modifiers (aka variants)
- Globals
- Theming
import { css } from 'trousers';
const styles = css({
background: 'grey',
color: 'black',
}).modifier('primary', {
background: 'red',
color: 'white',
});
import { css } from 'trousers';
const styles = css({
backgroundColor: 'red',
color: 'white',
':hover': {
backgroundColor: 'blue',
},
':active': {
backgroundColor: 'green',
},
});
import { css } from 'trousers';
const styles = css({
backgroundColor: 'red',
color: 'white',
'@media screen and (max-width: 992px)': {
'&': {
background: 'violet',
},
},
});
import { css } from 'trousers';
const styles = css({
backgroundColor: 'red',
color: 'white',
animation: 'moveitmoveit 5s infinite',
'@keyframes moveitmoveit': {
from: { top: '0px' },
to: { top: '200px' },
},
});
import { css } from 'trousers';
const styles = css('MyElement', { color: 'var(--primary-color)' })
.modifier('Primary', { color: 'var(--secondary-color)' })
.theme({
primaryColor: 'red',
secondaryColor: 'blue',
});
Every app needs some form of global styling in order to import fonts or reset native styling, for example using @font-face would be quite challenging to use without access to globals.
This is where the css.global
function can help.
/** @jsx jsx */
import { css, jsx } from 'trousers';
const globalStyles = css({}).global({
'*': {
boxSizing: 'border-box';
}
});
const App = () => (
<div css={globalStyles}>
<h1>Welcome to my website!</h1>
</div>
);
Trousers supports a css prop, similar to that of emotion and styled-components!
Just remember to import jsx
and set it as the pragma at the top of the file.
/** @jsx jsx */
import { jsx, css } from 'trousers';
const Button = ({ children }) => (
<button
css={css({
backgroundColor: 'red',
color: 'white',
})}
>
{children}
</button>
);
Trousers in it's default state is a run-time library, even some CSS-in-JS libraries that boast near-zero runtime have hundreds of lines of code to execute before they mount a style block to the page. Trousers is no different, that's why we provide and recommend using our babel macro: @trousers/macro
.
@trousers/macro
is the most performant version of Trousers! It drastically reduces the runtime implications of the library by offloading the heavy style processing logic to build-time where possible! Namespacing, prefixing and processing are all handled by the macro at build time, leaving us with simply mounting and toggling classes π.
For more information see: @trousers/macro
Trousers is based on a monorepo architecture, meaning that the internals of the repo have been decomposed into a group of smaller stand-alone packages. Doing this will reduce your bundlesizes and tailor (lol) Trousers to suit your needs.
If you're looking to use Trousers for the first time, you'll likely want the trousers
package.
If run-time is your concern, you want the most performant version of the library, consider using @trousers/macro
.
If you're feeling adventurous and want to use the Trousers to create your own CSS-in-JS library or even take it in your own direction, use @trousers/core
.
Trousers discourages the use of dynamic expressions in styles that implicitly increase the runtime implications of your application. Instead, it encourages the use of modifiers (aka variants) to toggle blocks of styles.
You might have seen this pattern emerging in some usages of CSS-in-JS:
styled.button`
background: ${props => (props.primary ? 'red' : 'grey')}
color: ${props => (props.primary ? 'white' : 'black')};
font-size: 1em;
margin: 1em;
`;
What's happening here is that we're calculating the two properties individually, with runtime logic. This is ok for this small usage, but you can probably see how quickly this will get complicated as new variants are added over time. Not to meantion that for every permutation of these properties a new class will be calculated and mounted to the page.
Trousers discourages dynamic interpolations like this and instead provides modifiers to help you fall into the right patterns. Only one class will be calculated and mounted per modifier and they're structured to be easier reason about at a glance.
const styles = css({
background: 'grey',
color: 'black',
fontSize: '1em',
margin: '1em',
}).modifier('primary', {
background: 'red',
color: 'white',
});
With this, you can now clearly see that this style block has two different variants 'default' and 'primary', which will only ever process and mount 2 classes to the page, it's clear what properties are applied to which scenarios when.
For a more in depth explanation read my motivation blog post: CSS-in-JS: What happened to readability
For API documentation, please refer to the relevant package README.
trousers
: Is the base packages which re-exports all of the modules in the sub-packages@trousers/macro
: (Recommended) Babel macro that moves 99% of Trousers' run-time logic to build-time!@trousers/core
: Holds all of the underlying logic of trousers, including the css collector.@trousers/react
: React implementation of Trousers@trousers/styled
: Styled Components like API@trousers/sheet
: Mount styles via the CSSStyleSheet API (CSSOM wrapper)@trousers/hash
: A tiny hashing function
Please do yourself a favour and checkout these fantastic libraries: