Emotion
Emotion is a tool for doing CSS-in-JS • https://emotion.sh
Emotion is our styling tool of choice for webapps. Use Emotion if you need CSS styles that aren’t in or appropriate to put in Fleet.
CSS-in-JS is attractive for us because it lets us write CSS that is co-located with our React components. Emotion styles are scoped to the component where they’re used, so it’s very easy to reason about the effects changing the styles would cause.
We picked Emotion over Next.js’s default styled-jsx because the latter is still reliant on user-generated class names to associate styles with components, which means that you a) have to come up with them; b) risk conflicting with other class names; and c) don’t get automatic dead code detection the way you do when you stop referencing an Emotion style.
Emotion Toolchain
We have two helpers that make using Emotion better and safer.
The jest-emotion
package interprets Emotion class names in Jest snapshots (such as those generated by StoryShots). It unrolls the CSS so that it gets diffed in the snapshot. Without it, CSS changes only appear in the snapshots as generated class name changes.
We use the eslint-plugin-emotion
package with ESLint to enforce setting the proper /** @jsx jsx */
pragma and @emotion/core
import statements when the Emotion 10 css
prop is used (see below).
Emotion does have two Babel plugins, but we’ve decided against using them. The babel-emotion
plugin generates slightly nicer class names and can make source maps. The @emotion/babel-preset-css-prop
preset includes babel-emotion
and also automatically uses the @emotion/core
jsx
factory for all JSX so you can use css
props.
We like to avoid Babel plugins because they introduce magic that can be hard to track down. We’re much happier with the solution of having eslint-plugin-emotion
add /** @jsx */
pragmas for us, since it’s nearly as automatic but significantly more transparent as to what’s happening.
Emotion 10 Migration
Emotion released a new version, 10, that makes use of a JSX factory to support a css
prop on React components. When styles are applied via the css
prop, no extra work needs to be done to automatically inject <style>
elements for server-side rendering.
Currently, all of our webapps use the emotion
package, which uses the pre-10 API. With this API, the css()
method returns a string for the style’s auto-generated class name. We use these values in className
attributes in the JSX, often in template literals when they are composed with other class names. These apps also have code in _document.tsx
and _app.tsx
to handle the server-side rendering (and to set up a CacheProvider
for legacy compatibility).
react-fleet
has been updated to use css()
from @emotion/core
, which generates a style object that needs to get applied via the css
prop. It is therefore ready for when we start using the version 10 API in our apps.
It would be nice in general to use version 10 because that lets us remove the awkward SSR support. Given the backwards compatibility interface of the emotion
package, it’s not worth actively converting old apps. New apps, however, should start from the ground-up using the css
prop.
Last updated