Skip to Content

Devin Clark

JavaScript Styling with Feeling

This is a quick introduction to how I did CSS-in-JS on a recent project using Emotion and Preact.

To start, I need to install emotion and a Babel plugin. The Babel plugin generates source maps and optimizes style output. Emotion highly recommends this for production use.

npm install --save emotion
npm install --save-dev babel-plugin-emotion

Create a .babelrc file (or add the emotion parts to my existing babelrc file). Source maps will add a lot of weight to my bundle, so I am disabling them in production.

{
"env": {
"production": {
"plugins": [["emotion", { "sourceMap": false }]]
},
"development": {
"plugins": [["emotion", { "sourceMap": true }]]
}
}
}

Now, I can start making components. I've made a basic component to define a section with padding on the bottom. I prefer defining the styles as objects instead of template tags. It feels more natural in JavaScript to me. I wrap all the styles in a styles object. The individual items in the style object are wrapped in emotion's css function.

import { css } from 'emotion';
import { h } from 'preact';
import { GRID_UNIT } from '../constants/layout';

const styles = {
container: css({
paddingBottom: GRID_UNIT * 5,
}),
};

export default function Section() {
return <section className={styles.container}>{props.children}</section>;
}

GRID_UNIT is a constant I have defined with a value of 8. I make all my dimensions, margins, and padding a multiple of this number. Because of this I am able to get a very uniform interface without much effort.

To use the styles, I just pass the style I want to className. If I need to do any kind of composition I can use cx from emotion and pass an array of styles that are merged together. cx uses the classnames API.

import { css, cx } from 'emotion';
import { h } from 'preact';
import { GRID_UNIT } from '../constants/layout';

const styles = {
container: css({
fontSize: 20,
paddingBottom: GRID_UNIT * 3,
}),
};

export default function SectionHeading(props) {
return <h2 className={cx(styles.container, props.className)}>{props.children}</h2>;
}

By passing props.className to cx I can override the default styles.

const styles = {
specialHeading: css({
fontSize: 22,
color: 'blue',
}),
};

<SectionHeading className={styles.specialHeading}>Very Special Heading</SectionHeading>;

Next, I use injectGlobal to do a simple CSS reset.

import { injectGlobal } from 'emotion';

injectGlobal({
html: {
boxSizing: 'border-box',
},

'*': {
boxSizing: 'inherit',
margin: 0,
padding: 0,

':before': {
boxSizing: 'inherit',
},

':after': {
boxSizing: 'inherit',
},
},
});

Being able to snapshot test the styles using jest-emotion is a big plus for me too. You can read more about that on the Emotion docs.

Photo of Devin Clark
Devin Clark
Principal Software Engineer, Oracle
You Might Also Like