What is emotion?
Emotion is a performant and flexible CSS-in-JS library that allows you to style applications quickly and efficiently with JavaScript. It provides powerful and flexible tools for writing CSS styles with JavaScript, including support for styled components, CSS prop, and keyframes for animations.
What are emotion's main functionalities?
Styled Components
Styled components allow you to create React components with styles attached to them. This makes it easy to manage styles in a modular and reusable way.
const Button = styled.button`
color: hotpink;
`;
<Button>Click me</Button>
CSS Prop
The CSS prop allows you to style elements using a prop directly in your JSX. This is useful for applying styles conditionally or dynamically.
<div css={{ color: 'hotpink' }}>Hello World</div>
Keyframes for Animations
Emotion provides support for keyframes, allowing you to define animations in your JavaScript code. This makes it easy to create complex animations and apply them to your components.
import { keyframes } from '@emotion/react';
const bounce = keyframes`
from, 20%, 53%, 80%, to {
transform: translate3d(0,0,0);
}
40%, 43% {
transform: translate3d(0, -30px, 0);
}
70% {
transform: translate3d(0, -15px, 0);
}
90% {
transform: translate3d(0,-4px,0);
}
`;
const BouncingDiv = styled.div`
animation: ${bounce} 1s ease infinite;
`;
<BouncingDiv>Bounce!</BouncingDiv>
Other packages similar to emotion
styled-components
Styled-components is another popular CSS-in-JS library that allows you to write plain CSS in your JavaScript. It offers a similar API to Emotion's styled components and is widely used in the React community.
aphrodite
Aphrodite is a CSS-in-JS library developed by Khan Academy. It focuses on performance and provides a straightforward API for defining styles in JavaScript. It is less feature-rich compared to Emotion but is known for its simplicity and performance.
jss
JSS is a library for generating CSS from JavaScript. It provides a powerful and flexible API for defining styles and supports various plugins for additional functionality. JSS is highly customizable and can be used with various frameworks, not just React.
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 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>
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|%