The recent major version of Emotion, a CSS-in-JS library, is a massive and long-awaited release with new features, improvements and bug fixes. A number of major features stand out. Components can now be styled with the css
property (prop) in a larger set of contexts, with a more natural syntax which allows access to the theme properties. A new Global
component enables dynamic global styling. Those changes contribute to enabling zero-configuration server-side rendering.
Emotion 10.0 no longer requires using a Babel plugin to use the css
prop in styled components. As a result, developers using the Emotion library may use projects that do not allow custom Babel configurations (Create React App, code playgrounds such as codesandbox.io
, and more). It is now possible to set the Emotion’s jsx
pragma at the top of the source file that uses the css
prop:
/** @jsx jsx */
import { jsx } from '@emotion/core'
Style precedence is now fixed and documented in Emotion 10.0. The precedence rules are chosen so that components with styles defined on their css
prop may be customized via the className
prop passed from the parent. The documentation summarizes the precedence rules:
- Class names containing Emotion styles from the
className
prop overridecss
prop styles.- Class names from sources other than Emotion are ignored and appended to the computed Emotion class name.
and gives an illustrative example. The P
component thereafter has its default styles overridden in the ArticleText
component, and the same occurs with SmallArticleText
which is a specialization of ArticleText
:
/** @jsx jsx */
import { jsx } from '@emotion/core'
const P = props => (
<p
css={{
margin: 0,
fontSize: 12,
lineHeight: '1.5',
fontFamily: 'sans-serif',
color: 'black'
}}
{...props} // <- props contains the `className` prop
/>
)
const ArticleText = props => (
<P
css={{
fontSize: 14,
fontFamily: 'Georgia, serif',
color: 'darkgray'
}}
{...props} // <- props contains the `className` prop
/>
)
const SmallArticleText = props => (
<ArticleText
css={{
fontSize: 10
}}
{...props} // <- props contains the `className` prop
/>
)
As expected, and in line with the CSS specification’s Order of Appearance rule, property values defined last (+
) override those defined first (-
):
.css-result {
+ margin: 0;
- font-size: 12px;
+ line-height: 1.5;
- font-family: 'sans-serif';
- color: black;
- font-size: 14px,
+ font-family: Georgia, serif,
+ color: darkgray;
+ font-size: 10px;
}
The CSS for the SmallArticleText
will include the styling received from P
(margin: 0
) and ArticleText
(color: 'darkgray'
). However, the font size (font-size: 10px
) defined for SmallArticleText
will override the font size defined higher in the component hierarchy. Similarly, the color style defined in ArticleText
overrides the one defined in its parent P
(color: 'black'
).
As stated by the second precedency rules, class names from sources other than Emotion do not impact the precedence resolution.
Emotion 10.0 now accepts components that simultaneously have a css
property and other properties passed through the object spread syntax. The css
prop also accepts a functional syntax which exposes the theme properties. The release note gives the following example:
/** @jsx jsx */
import { jsx } from "@emotion/core";
import { ThemeProvider } from "emotion-theming";
import { render } from "react-dom";
function Header(props) {
return (
<h1
css={theme => ({
fontSize: 48,
fontWeight: 600,
color: theme.colors.header
})}
{...props}
/>
);
}
function BodyText(props) {
return (
<p
css={theme => ({
color: theme.colors.primary,
fontFamily: "sans-serif",
fontSize: 18,
"&:hover": {
color: theme.colors.hover
}
})}
{...props}
/>
);
}
function App() {
return (
<ThemeProvider
theme={{
colors: {
primary: "hotpink",
hover: "crimson",
header: "dimgray"
}
}}
>
<div>
<Header>Header Title</Header>
<BodyText>Hello Emotion 10!!!</BodyText>
</div>
</ThemeProvider>
);
}
render(<App />, document.getElementById("root"));
The example showcases the css
prop functional syntax (css={theme => ({...
), and the co-location of the object spread syntax with the css
prop (<p css={theme => (...) {...props} />
).
The new Global
component enables dynamic update or removal of global styling. The corresponding feature documentation illustrates:
import { Global, css } from '@emotion/core'
render(
<div>
<Global
styles={css`
* {
color: hotpink !important;
}
`}
/>
<Global
styles={{
'.some-class': {
fontSize: 50,
textAlign: 'center'
}
}}
/>
<div className="some-class">
Everything is hotpink now!
</div>
</div>
)
The displayed div
will show a centered pink text. Global styles are updated/removed when the styles change or when the Global
component unmounts.
Zero-configuration server-side rendering is enabled by the previously described changes. The release note states:
If you’re using the new
css
prop orstyled
, you don’t need to do anything other than calling React’srenderToString
(orrenderToNodeStream
). This is especially exciting for component libraries because consumers don’t need to do anything special to use a component.
You can now publish a React component to NPM with styles, and it will just work with server-side rendering without requiring consumers to do anything.
Emotion 10.0 includes many more changes, improvements, and bug fixes. A migration guide aims at facilitating an incremental upgrade to the new APIs. The migration guide is supported by an ESLint plugin which automates part of the upgrades.
CSS-in-JS refers to a pattern where CSS is composed using JavaScript instead of defined in external CSS files. Emotion is a runtime CSS-in-JS library which allows definition of component style with an object or CSS-like string style. Runtime CSS-in-JS libraries, such as Emotion or Styled-components, dynamically modify styles at runtime, for instance by injecting style tags into the document. Zero-runtime CSS-in-JS libraries, such as Linaria, or Astroturf extract all the CSS at build time.
Emotion is an open source project available under the MIT license. Contributions are welcome via the Emotion GitHub project and should follow the Emotion code of conduct and contributions guidelines.