DEV Community

Darcy
Darcy

Posted on

An intro to CSS-in-JS libraries

As so many inspired by Christopher Chedeau's talk on Facebook's use of CSS in JS, many libraries have emerged as a way of implementing the methodology. In fact, when selecting a library, you may yourself slightly overwhelmed with the number of options available.

At the core of each of the libraries is the ability to use them with modern component-based applications. The aim of this article to provide an outline and comparison of four of the libraries that I've used most often:

  • Styled-Components
  • Emotion
  • Glamor
  • Aphrodite

Summary

Library Template Literal Object Literal Automatic Vendor Prefixing Server-Side Rendering ClassName Required
styled-components tick tick tick tick cross
Emotion tick tick tick tick cross
Glamor cross tick tick tick tick
Aphrodite cross tick tick tick tick

From the table above, it is clear that many of the key features are shared by all the libraries. In fact, I often find myself choosing a particular CSS-in-JSS library based on syntactic reasons. At the time of writing, that means using styled-components for converting preexisting projects to React (for the ability to use template literals) and Aphrodite for new projects (for, in my opinion, it's clearer separation of CSS and JS logic).

Template Literal vs Object Literal

At the time of writing, only styled-components and Emotion allow you to write styles as template literals. This is a significant advantage for when you are converting an existing codebase to React, as it forces you to do very little modification of the CSS.

Template Literal

// Using template literal string in Emotion
const base = css`
  color: hotpink;
`

render(
  <div
    css={css`
      ${base};
      background-color: #eee;
    `}
  >
    This is hotpink.
  </div>
)

Object Literal

// using Object Literal styles in Emotion

const Button = styled.button(
  {
    color: 'darkorchid'
  },
  props => ({
    fontSize: props.fontSize
  })
)

render(
  <Button fontSize={16}>
    This is a darkorchid button.
  </Button>
)

Syntactic Differences

In comparing the syntactic differences between the libraries, it is best to replicate the same element. For these purposes, I will be creating two buttons of different colors.

Styled-Components

import React from 'react';
import styled, { css } from 'styled-components';

const Button = styled.button`
  background: transparent;
  border-radius: 3px;
  border: 2px solid #007bff;
  color: #007bff;
  margin: 0.5em 1em;
  padding: 0.25em 1em;

  ${props => props.primary && css`
    background: #007bff;
    color: white;
  `}
`;

const StyledComponentsLib = () => {
  return (
    <div>
      <Button>Normal Button</Button>
      <Button primary>Primary Button</Button>
    </div>
  );
};

export default StyledComponentsLib;

Emotion

import React from 'react';
import styled from '@emotion/styled';
import { css } from '@emotion/core';

const Button = styled.button`
  background: transparent;
  border-radius: 3px;
  border: 2px solid #007bff;
  color: #007bff;
  margin: 0.5em 1em;
  padding: 0.25em 1em;

  ${props => props.primary && css`
    background: #007bff;
    color: white;
  `}
`;

const EmotionLib = () => {
  return (
    <div>
      <Button>Normal Button</Button>
      <Button primary>Primary Button</Button>
    </div>
  );
};

export default EmotionLib;

Glamor

import React from 'react';
import { css } from 'glamor';

const Button = (props) => {
  const myButton = css({
    background: 'transparent',
    color: '#007bff',
    borderRadius: '3px',
    border: '2px solid #007bff',
    margin: '0.5em 1em',
    padding: '0.25em 1em'
  });

  return (
    <button className={css(myButton, props.css)}>{ props.children }</button>
  );
};

const GlamorLib = () => {
  const primaryButton = css({
    background: '#007bff',
    color: 'white'
  });

  return (
    <div>
      <Button>Normal Button</Button>
      <Button css={primaryButton}>
        Primary Button
     </Button>
    </div>
  );
};

export default GlamorLib;

Aphrodite

import React from 'react';
import { StyleSheet, css } from 'aphrodite';

const styles = StyleSheet.create({
  myButton: {
    background: 'transparent',
    color: '#007bff',
    borderRadius: '3px',
    border: '2px solid #007bff',
    margin: '0.5em 1em',
    padding: '0.25em 1em'
  },
  primary: {
    background: '#007bff',
    color: 'white'
  }
});

const Button = (props) => {
  const primaryButton = props.primary && styles.primary;

  return (
    <button className={css(styles.myButton, primaryButton)}>
      { props.children }
    </button>
  );
};

const AphroditeLib = () => {
  return (
    <div>
      <Button>Normal Button</Button>
      <Button primary>Primary Button</Button>
    </div>
  );
};

export default AphroditeLib;

Latest comments (0)