A curated list of the best Styling libraries.
1. radium
Radium is a set of tools to manage inline styles on React elements.
yarn add radium
# or
npm install --save radium
It gives you powerful styling capabilities without CSS.
Overview
Eliminating CSS in favor of inline styles that are computed on the fly is a powerful approach, providing a number of benefits over traditional CSS:
- Scoped styles without selectors
- Avoids specificity conflicts
- Source order independence
- Dead code elimination
- Highly expressive
Despite that, there are some common CSS features and techniques that inline styles don't easily accommodate: media queries, browser states (:hover, :focus, :active) and modifiers (no more .btn-primary!). Radium offers a standard interface and abstractions for dealing with these problems.
When we say expressive, we mean it: math, concatenation, regex, conditionals, functionsโJavaScript is at your disposal. Modern web applications demand that the display changes when data changes, and Radium is here to help.
Features
- Conceptually simple extension of normal inline styles
- Browser state styles to support
:hover
,:focus
, and:active
- Media queries
- Automatic vendor prefixing
- Keyframes animation helper
- ES6 class and
createClass
support
How does Radium work?
Following is a short technical explanation of Radium's inner workings:
- Wrap the
render
function - Recurse into the result of the original
render
- For each element:
- Add handlers to props if interactive styles are specified, e.g.
onMouseEnter
for:hover
, wrapping existing handlers if necessary - If any of the handlers are triggered, e.g. by hovering, Radium calls
setState
to update a Radium-specific field on the components state object - On re-render, resolve any interactive styles that apply, e.g.
:hover
, by looking up the element's key or ref in the Radium-specific state
- Add handlers to props if interactive styles are specified, e.g.
Usage
Start by wrapping your component class with Radium()
, like export default Radium(Component)
, or Component = Radium(Component)
, which works with classes, createClass
, and stateless components (functions that take props and return a ReactElement). Then, write a style object as you normally would with inline styles, and add in styles for interactive states and media queries. Pass the style object to your component via style={...}
and let Radium do the rest!
<Button kind="primary">Radium Button</Button>
import Radium from 'radium';
import React from 'react';
import color from 'color';
class Button extends React.Component {
static propTypes = {
kind: PropTypes.oneOf(['primary', 'warning']).isRequired
};
render() {
// Radium extends the style attribute to accept an array. It will merge
// the styles in order. We use this feature here to apply the primary
// or warning styles depending on the value of the kind
prop. Since its
// all just JavaScript, you can use whatever logic you want to decide which
// styles are applied (props, state, context, etc).
return (
<button style={[styles.base, styles[this.props.kind]]}>
{this.props.children}
</button>
);
}
}
Button = Radium(Button);
// You can create your style objects dynamically or share them for
// every instance of the component.
var styles = {
base: {
color: '#fff',
// Adding interactive state couldn't be easier! Add a special key to your
// style object (:hover, :focus, :active, or @media) with the additional rules.
':hover': {
background: color('#0074d9')
.lighten(0.2)
.hexString()
}
},
primary: {
background: '#0074D9'
},
warning: {
background: '#FF4136'
}
};
Importing Radium
As of v0.22.x
, Radium is built as an ECMAScript Modules-first project. We now have a package.json:module
entry pointing to our library files with import|export
statements instead of CommonJS require
s. We still support CommonJS require
s with a special package.json:main
entry pointing to root index.js
to smooth over this transition. The basic takeaways are:
If you are using ESM with webpack or @std/esm
with Node.js, imports like the following work fine without any gotchas:
import Radium from 'radium';
import Radium, {Style} from 'radium';
If you are using CommonJS with Node.js or [email protected] requires work like normal:
const Radium = require('radium');
const {Style} = require('radium');
If you are using CommonJS with [email protected]+, however, you must instead add .default
to the root Radium
object import:
const Radium = require('radium').default; // CHANGED: Must add .default
const {Style} = require('radium'); // Works as per normal
If you cannot change the require
statements directly (say Radium is included from a different library your project depends on) you can manually tweak the Radium import in your project's webpack configuration with the following:
resolve: {
alias: {
radium: require.resolve('radium/index');
}
}
which will allow const Radium = require('radium');
to still work. The configuration effectively forces webpack to point to code from package.json:main
(which points to /index.js
) instead of what is in package.json:module
.
Note: Radium uses Reflect
which is not supported in IE11. You will need to bring in a polyfill like CoreJs in order to support <IE11.
Read more
2. aphrodite
Framework-agnostic CSS-in-JS with support for server-side rendering, browser prefixing, and minimum CSS generation.
Support for colocating your styles with your JavaScript component.
- Works great with and without React
- Supports media queries without window.matchMedia
- Supports pseudo-selectors like
:hover
,:active
, etc. without needing to
store hover or active state in components.:visited
works just fine too. - Supports automatic global
@font-face
detection and insertion. - Respects precedence order when specifying multiple styles
- Requires no AST transform
- Injects only the exact styles needed for the render into the DOM.
- Can be used for server rendering
- Few dependencies, small (20k, 6k gzipped)
- No external CSS file generated for inclusion
- Autoprefixes styles
Installation
Aphrodite is distributed via npm:
npm install --save aphrodite
API
If you'd rather watch introductory videos, you can find them here.
import React, { Component } from 'react';
import { StyleSheet, css } from 'aphrodite';
class App extends Component {
render() {
return <div>
<span className={css(styles.red)}>
This is red.
</span>
<span className={css(styles.hover)}>
This turns red on hover.
</span>
<span className={css(styles.small)}>
This turns red when the browser is less than 600px width.
</span>
<span className={css(styles.red, styles.blue)}>
This is blue.
</span>
<span className={css(styles.blue, styles.small)}>
This is blue and turns red when the browser is less than
600px width.
</span>
</div>;
}
}
const styles = StyleSheet.create({
red: {
backgroundColor: 'red'
},
blue: {
backgroundColor: 'blue'
},
hover: {
':hover': {
backgroundColor: 'red'
}
},
small: {
'@media (max-width: 600px)': {
backgroundColor: 'red',
}
}
});
Conditionally Applying Styles
Note: If you want to conditionally use styles, that is simply accomplished via:
const className = css(
shouldBeRed() ? styles.red : styles.blue,
shouldBeResponsive() && styles.small,
shouldBeHoverable() && styles.hover
)
<div className={className}>Hi</div>
This is possible because any falsey arguments will be ignored.
Combining Styles
To combine styles, pass multiple styles or arrays of styles into css()
. This is common when combining styles from an owner component:
class App extends Component {
render() {
return <Marker styles={[styles.large, styles.red]} />;
}
}
class Marker extends Component {
render() {
// css() accepts styles, arrays of styles (including nested arrays),
// and falsy values including undefined.
return <div className={css(styles.marker, this.props.styles)} />;
}
}
const styles = StyleSheet.create({
red: {
backgroundColor: 'red'
},
large: {
height: 20,
width: 20
},
marker: {
backgroundColor: 'blue'
}
});
Resetting Style Cache
The reset
function can be used to reset the HTML style tag, injection buffer, and injected cache. Useful when Aphrodite needs to be torn down and set back up.
import { reset } from 'aphrodite';
reset();
While the resetInjectedStyle
function can be used to reset the injected cache for a single key (usually the class name).
import { resetInjectedStyle } from 'aphrodite';
resetInjectedStyle('class_1sAs8jg');
Server-side rendering
To perform server-side rendering, make a call to StyleSheetServer.renderStatic
, which takes a callback. Do your rendering inside of the callback and return the generated HTML. All of the calls to css()
inside of the callback will be collected and the generated css as well as the generated HTML will be returned.
Rehydrating lets Aphrodite know which styles have already been inserted into the page. If you don't rehydrate, Aphrodite might add duplicate styles to the page.
To perform rehydration, call StyleSheet.rehydrate
with the list of generated class names returned to you by StyleSheetServer.renderStatic
.
Note: If you are using aphrodite/no-important
in your project and you want to render it on server side, be sure to import StyleSheetServer
from aphrodite/no-important
otherwise you are going to get an error.
As an example:
import { StyleSheetServer } from 'aphrodite';
// Contains the generated html, as well as the generated css and some
// rehydration data.
var {html, css} = StyleSheetServer.renderStatic(() => {
return ReactDOMServer.renderToString(<App/>);
});
// Return the base HTML, which contains your rendered HTML as well as a
// simple rehydration script.
return `
<html>
<head>
<style data-aphrodite>${css.content}</style>
</head>
<body>
<div id='root'>${html}</div>
<script src="./bundle.js"></script>
<script>
StyleSheet.rehydrate(${JSON.stringify(css.renderedClassNames)});
ReactDOM.render(<App/>, document.getElementById('root'));
</script>
</body>
</html>
`;
3. linaria
Here are its features:
- Write CSS in JS, but with zero runtime, CSS is extracted to CSS files during build
- Familiar CSS syntax with Sass like nesting
- Use dynamic prop based styles with the React bindings, uses CSS variables behind the scenes
- Easily find where the style was defined with CSS sourcemaps
- Lint your CSS in JS with stylelint
- Use JavaScript for logic, no CSS preprocessor needed
- Optionally use any CSS preprocessor such as Sass or PostCSS
- Supports atomic styles with
@linaria/atomic
Installation
npm install @linaria/core @linaria/react @linaria/babel-preset
or
yarn add @linaria/core @linaria/react @linaria/babel-preset
Setup
Linaria currently supports webpack and Rollup to extract the CSS at build time.
Optionally, add the code>@linaria</code preset to your Babel configuration at the end of the presets list to avoid errors when importing the components in your server code or tests:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react",
"@linaria"
]
}
Syntax
Linaria can be used with any framework, with additional helpers for React. The basic syntax looks like this:
import { css } from '@linaria/core';
import { modularScale, hiDPI } from 'polished';
import fonts from './fonts';
// Write your styles in css
tag
const header = css`
text-transform: uppercase;
font-family: ${fonts.heading};
font-size: ${modularScale(2)};
${hiDPI(1.5)} {
font-size: ${modularScale(2.5)};
}
`;
// Then use it as a class name
<h1 className={header}>Hello world</h1>;
You can use imported variables and functions for logic inside the CSS code. They will be evaluated at build time.
If you're using React, you can use the styled
helper, which makes it easy to write React components with dynamic styles with a styled-component like syntax:
import { styled } from '@linaria/react';
import { families, sizes } from './fonts';
// Write your styles in styled
tag
const Title = styled.h1`
font-family: ${families.serif};
`;
const Container = styled.div`
font-size: ${sizes.medium}px;
color: ${props => props.color};
border: 1px solid red;
&:hover {
border-color: blue;
}
${Title} {
margin-bottom: 24px;
}
`;
// Then use the resulting component
<Container color="#333">
<Title>Hello world</Title>
</Container>;
Dynamic styles will be applied using CSS custom properties (aka CSS variables) and don't require any runtime.
Demo
4. emotion
The Next Generation of CSS-in-JS.
Emotion is a performant and flexible CSS-in-JS library. Building on many other CSS-in-JS libraries, it allows you to style apps quickly with string or object styles. It has predictable composition to avoid specificity issues with CSS.
With source maps and labels, Emotion has a great developer experience and great performance with heavy caching in production.
๐ Demo Sandbox
๐ Docs
Quick Start
Get up and running with a single import.
npm install --save @emotion/react
/** @jsx jsx */
import { jsx } from '@emotion/react'
let SomeComponent = props => {
return (
<div
css={{
color: 'hotpink'
}}
{...props}
/>
)
}
5. stitches
Stitches allows you to Style your components with confidence.
CSS-in-JS with near-zero runtime, SSR, multi-variant support, and a best-in-class developer experience.
Stitches Core
Framework-agnostic implementation.
npm install @stitches/core
Stitches React
React wrapper including the styled
API.
npm install @stitches/react
6. vanilla-extract
Zero-runtime Stylesheets-in-TypeScript.
It allows you to Write your styles in TypeScript (or JavaScript) with locally scoped class names and CSS Variables, then generate static CSS files at build time.
Basically, itโs โCSS Modules-in-TypeScriptโ but with scoped CSS Variables + heaps more.
๐ฅ All styles generated at build time โ just like Sass, Less, etc.
โจ Minimal abstraction over standard CSS.
๐ฆ Works with any front-end framework โ or even without one.
๐ณ Locally scoped class names โ just like CSS Modules.
๐ Locally scoped CSS Variables, code>@keyframes</code and code>@font-face</code rules.
๐จ High-level theme system with support for simultaneous themes. No globals!
๐ Utils for generating variable-based calc
expressions.
๐ช Type-safe styles via CSSType.
๐โโ๏ธ Optional runtime version for development and testing.
๐ Optional API for dynamic runtime theming.
๐ฅ Try it out for yourself in CodeSandbox.
Write your styles in .css.ts
files.
// styles.css.ts
import { createTheme, style } from '@vanilla-extract/css';
export const [themeClass, vars] = createTheme({
color: {
brand: 'blue'
},
font: {
body: 'arial'
}
});
export const exampleStyle = style({
backgroundColor: vars.color.brand,
fontFamily: vars.font.body,
color: 'white',
padding: 10
});
๐ก Once you've configured your build tooling, these
.css.ts
files will be evaluated at build time. None of the code in these files will be included in your final bundle. Think of it as using TypeScript as your preprocessor instead of Sass, Less, etc.
Then consume them in your markup.
// app.ts
import { themeClass, exampleStyle } from './styles.css.ts';
document.write(`
<section class="${themeClass}">
<h1 class="${exampleStyle}">Hello world!</h1>
</section>
`);
7. styled-components
Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress.
Utilizing tagged template literals (a recent addition to JavaScript) and the power of CSS, styled-components
allow you to write actual CSS code to style your components. It also removes the mapping between components and styles โ using components as a low-level styling construct could not be easier!
const Button = styled.button`
color: grey;
`;
Alternatively, you may use style objects. This allows for easy porting of CSS from inline styles, while still supporting the more advanced styled-components capabilities like component selectors and media queries.
const Button = styled.button({
color: 'grey',
});
Equivalent to:
const Button = styled.button`
color: grey;
`;
styled-components
is compatible with both React (for web) and React Native โ meaning it's the perfect choice even for truly universal apps! See the documentation about React Native for more information.
Example
import React from 'react';
import styled from 'styled-components';
// Create a <Title> react component that renders an <h1> which is
// centered, palevioletred and sized at 1.5em
const Title = styled.h1`
font-size: 1.5em;
text-align: center;
color: palevioletred;
`;
// Create a <Wrapper> react component that renders a <section> with
// some padding and a papayawhip background
const Wrapper = styled.section`
padding: 4em;
background: papayawhip;
`;
// Use them like any other React component โ except they're styled!
<Wrapper>
<Title>Hello World, this is my first styled component!</Title>
</Wrapper>
This is what you'll see in your browser: