emotion
high performance js for your css
Install
npm install -S emotion
.babelrc
{
"plugins": [
"emotion/babel"
]
}
The default settings enable css extraction.
This js file, h1.js
import styled from 'emotion/react'
const H1 = styled('h1')`
color: #ffd43b;
`
During babel compilation emotion will create h1.emotion.css
and add import './h1.emotion.css'
to the top of h1.js
.css-H1-duiy4a {
color: blue
}
h1.js
after babel compilation
import './h1.emotion.css'
import styled from 'emotion/react'
const H1 = styled('h1', 'css-H1-duiy4a')
Browser Support no ie11 support (css vars)
Inline Mode
Only extracts styles without dynamic values. (we're working on this)- No css var requirement
- Same speed as default mode in benchmarks
- Works with SSR
Extracted:
const H1 = styled('h1')`
color: #ffd43b;
`
Not extracted
const H1 = styled('h1')`
color: ${props => props.color};
`
Configure babel
.babelrc
{
"plugins": [
["emotion/babel", { "inline": true }]
]
}
This js file, h1.js
import styled from 'emotion/react'
const H1 = styled('h1')`
color: ${props => props.color};
`
h1.js
after babel compilation
import './h1.emotion.css'
import styled from 'emotion/react'
const H1 = styled('h1', 'css-H1-duiy4a', [props => props.color], function createEmotionStyles(x0) {
return [`.css-H1-duiy4a { color:${x0} }`]
})
Browser Support anything React supports
API
styled
import styled from 'emotion/react'
const H1 = styled('h1')`
color: blue;
font-size: 48px;
transform: scale(${props => props.scale});
`
function Greeting ({ name }) {
return <H1 scale={2}>Hello {name}</H1>
}
const H2 = styled(H1)`
font-size: ${fontSize * 2/3}px;
color: red;
`
function Greeting ({ name }) {
return <H2>Hello {name}</H2>
}
const H3 = styled.h3`
font-size: ${fontSize * 1/3}px;
color: red;
`
function Greeting ({ name }) {
return <H3>Hello {name}</H3>
}
const H1 = styled('h1')`
color: red;
`
function Greeting ({ name }) {
return <H1 innerRef={() => console.log('hello!')}>Hello {name}</H1>
}
css
css
takes in styles and returns a class name. It is the foundation of emotion.
const flex = css`
display: flex;
`
const justifyCenter = css`
composes: ${flex};
justifyContent: center;
`
<div className={justifyCenter}>
Centered Content
</div>
Objects as Styles
css
can also take an object as a parameter.
This allows you to use your existing object styles in the emotion ecosystem.
Another great benefit is that you can now use polished with emotion!
import { css } from 'emotion'
importimport { lighten, modularScale } from 'polished'
const cssA = {
color: lighten(0.2, '#000'),
"font-size": modularScale(1),
[hiDPI(1.5)]: {
"font-size": modularScale(1.25)
}
}
const cssB = css`
composes: ${cssA}
height: 64px;
`
const H1 = styled('h1')`
composes: ${cssB}
font-size: ${modularScale(4)};
`
const H2 = styled(H1)`font-size:32px;`
<H2 scale={2} className={'legacy__class'}>
hello world
</H2>
css prop
import { css } from 'emotion'
function SomeComponent (props) {
return (<div css={`
color: blue;
font-size: ${props.fontSize}px;
&:hover {
color: green;
}
& .some-class {
font-size: 20px;
}
`}>
This will be blue until hovered.
<div className="some-class">
This font size will be 20px
</div>
</div>)
}
composes property
The composes property is based on css modules' composes property.
import { fragment, css } from 'emotion'
import styled from 'emotion/react'
const flexCenter = css`
display: flex;
justify-content: center;
align-items: center;
`
const flexCenterClass = css`
composes: ${flexCenter};
flex-direction: column;
`
const FlexCenterComponent = styled.div`
composes: ${flexCenter};
`
const flexWrap = css`
flex-wrap: wrap;
`
const ColumnCenteredComponent = styled.div`
composes: ${flexCenter} ${flexWrap};
`
const CssModuleComponent = styled.h1`
composes: ${'some-class'} ${styles.header};
`
const cls = css`
font-size: 20px;
composes: ${flexCenter}
`
const cls = css`
& .flex {
composes: ${flexCenter}
}
`
keyframes
import { keyframes } from 'emotion'
import styled from 'emotion'
const bounce = keyframes`
from {
transform: scale(1.01);
}
to {
transform: scale(0.99);
}
`
const AnimatedDiv = styled.div`
animation: ${bounce} 0.2s infinite ease-in-out alternate;
`
fontFace
import { fontFace } from 'emotion'
fontFace`
font-family: 'Patrick Hand SC';
font-style: normal;
font-weight: 400;
src: local('Patrick Hand SC'), local('PatrickHandSC-Regular'), url(https://fonts.gstatic.com/s/patrickhandsc/v4/OYFWCgfCR-7uHIovjUZXsZ71Uis0Qeb9Gqo8IZV7ckE.woff2) format('woff2');
unicode-range: U+0100-024F, U+1E00-1EFF, U+20A0-20AB, U+20AD-20CF, U+2C60-2C7F, U+A720-A7FF;
`
Server-Side Rendering
Server-Side Rendering in emotion currently only works in inline mode. It's similar to glamor's api. For an example of emotion and next.js checkout the with-emotion example in the next.js repo.
This returns an object with the properties html
, ids
and css
. It removes unused rules that were created with emotion(it still includes rules that were inserted with injectGlobal
).
import { renderToString } from 'react-dom/server'
import { extractCritical } from 'emotion/server'
import App from './App'
const { html, ids, css } = extractCritical(renderToString(<App/>))
hydrate
hydrate
should be called on the client with the ids
that extractCritical
returns. If you don't call it then emotion will reinsert all the rules.
import { hydrate } from 'emotion'
hydrate(ids)
vue styled
<template>
<div id="app">
<styled-div>This should have a blue background.</styled-div>
<styled-component></styled-component>
</div>
</template>
<script>
import BoringComponent from './components/BoringComponent'
import styled from 'emotion/vue'
const StyledDiv = styled.div`
background: blue;
`
const StyledComponent = styled(BoringComponent)`
display: flex;
justify-content: center;
`
export default {
name: 'app',
components: {
'styled-div': StyledDiv,
'styled-component': StyledComponent
}
}
</script>
Usage with CSS Modules
emotion works well with CSS Modules but it requires a bit of configuration.
- In your webpack config add the exclude option with this regex
/emotion\.css$/
to your loader for css so that emotion's static css isn't imported as a CSS Module. - Add another object to your
modules.use
with your css loaders but with CSS Modules disabled and set the test field to the same regex as above /emotion\.css$/
.
attr
The attr CSS function is supported in
a basic capacity.
width: attr(width vw);
width: attr(width vw);
width: attr(width vw, 50);
const H1 = styled.h1`
font-size: attr(fontSize px);
margin: attr(margin rem, 4);
font-family: sans-serif;
color: attr(color, ${colors.pink[5]});
@media (min-width: 680px) {
color: attr(desktopColor);
}
`
const Title = ({ title, scale }) => {
return (
<H1 fontSize={16 * scale} desktopColor={colors.gray[5]}>
{title}
</H1>
)
}