Best ReactJS Styling Libraries

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

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 requires. We still support CommonJS requires 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>
`;

Read more


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

Edit Linaria Demo

Read more


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}
    />
  )
}

Read more


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

Read more

Stitches React

React wrapper including the styled API.

npm install @stitches/react

Read more


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>
`);

Read more


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:

Read more