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
Inline mode does not extract css into external files.
.babelrc
{
"plugins": [
["emotion/babel", { "inline": true }]
]
}
This js file, h1.js
import styled from 'emotion/react'
const H1 = styled('h1')`
color: #ffd43b;
`
h1.js
after babel compilation
import './h1.emotion.css'
import styled from 'emotion/react'
const H1 = styled('h1', 'css-H1-duiy4a', [], function createEmotionStyles() {
return ['.css-H1-duiy4a {color:blue}']
})
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 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>)
}
fragment
import { fragment, css } from 'emotion'
import styled from 'emotion/react'
const flexCenter = fragment`
display: flex;
justify-content: center;
align-items: center;
`
const flexCenterClass = css`
@apply ${flexCenter};
flex-direction: column;
`
const FlexCenterComponent = styled.div`
@apply ${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 based on glamor's api. For an example of emotion and next.js checkout the with-emotion example in the next.js repo.
renderStatic
This returns an object with the properties html
, ids
and css
.
import { renderToString } from 'react-dom/server'
import { renderStatic } from 'emotion/server'
import App from './App'
const { html, ids, css } = renderStatic(() => renderToString(<App/>))
renderStatic
This returns an object with the properties html
, ids
and css
just like renderStatic
but it remove unused rules that were created with emotion(it still includes rules that were inserted with injectGlobal
).
import { renderToString } from 'react-dom/server'
import { renderStaticOptimized } from 'emotion/server'
import App from './App'
const { html, ids, css } = renderStaticOptimized(() => renderToString(<App/>))
hydrate
hydrate
should be called on the client with the ids
that renderStatic
and renderStaticOptimized
return. 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>
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: ${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>
)
}
Supported value types
em|ex|px|rem|vw|vh|vmin|vmax|mm|cm|in|pt|pc|%