Twin 101: Use Tailwind CSS + CSS-in-JS in a Next.js App
Elvis Duru / March 5, 2022 (Updated on July 2, 2022)
4 min read • --- views
Introduction
Twin is a library that let’s you enjoy the best of Tailwind CSS together with CSS-in-JS libraries like emotion or styled-components. In this article I’ll walk you through how to setup Tailwind CSS and CSS-in-JS (emotion) in your Next.js app with twin.macro.
Installation
For this example we’ll be using Emotion as our CSS-in-JS library. There are two ways to get started with Twin. If you’re starting a new Next.js project you can simply download the next-emotion starter using the following command - remember to replace folder-name
with the name of your project:
npx degit https://github.com/ben-rogerson/twin.examples/next-emotion folder-name
This will clone the starter which has everything already setup and configured for you. Once that is done, you should navigate into the folder and run npm install
to install dependencies, then npm run dev
to start the dev server.
Existing Projects
For existing projects, we’ll have to install the dependencies and configure the project.
Step 1 - Install Dependencies
Run the following command to install the required dependencies:
npm install @emotion/react @emotion/styled @emotion/css @emotion/server
npm install -D twin.macro tailwindcss @emotion/babel-plugin babel-plugin-macros
Step 2 - Add the Global Styles
Twin comes with a GlobalStyles import that adds some the base styles from tailwind together with some @keyframes for animations, and some global css variables to alleviate cross-browser inconsistencies.
Create a new file in the path styles/GlobalStyles.js
and add the following:
import { Global, css } from '@emotion/react'
import tw, { theme, GlobalStyles as BaseStyles } from 'twin.macro'
const customStyles = css({
body: {
WebkitTapHighlightColor: theme`colors.purple.500`,
...tw`antialiased`,
},
})
const GlobalStyles = () => (
<>
<BaseStyles />
<Global styles={customStyles} />
</>
)
export default GlobalStyles
Next, import the GlobalStyles in pages/_app.js
:
import GlobalStyles from './../styles/GlobalStyles'
const App = ({ Component, pageProps }) => (
<>
<GlobalStyles />
<Component {...pageProps} />
</>
)
export default App
Step 3 - SSR Styles
To use emotion’s SSR with Next.js, we need to add a custom Document component in pages/_document.js
that renders critical styles and inserts them into the <head>
.
import React from 'react'
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { extractCritical } from '@emotion/server'
export default class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
const critical = extractCritical(initialProps.html)
initialProps.html = critical.html
initialProps.styles = (
<React.Fragment>
{initialProps.styles}
<style
data-emotion-css={critical.ids.join(' ')}
dangerouslySetInnerHTML={{ __html: critical.css }}
/>
</React.Fragment>
)
return initialProps
}
render() {
return (
<Html lang="en">
<Head>
<style
data-emotion-css={this.props.ids.join(' ')}
dangerouslySetInnerHTML={{ __html: this.props.css }}
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
Step 4 (Optional) - Adjusting Twin’s Config Options
The default preset is set to ‘emotion’, but if you want to adjust Twin’s other options, you can do so in any of the files below:
- Either in
babel-plugin-macros.config.js
module.exports = {
twin: {
preset: 'emotion',
},
}
- Or in
package.json
"babelMacros": {
"twin": {
"preset": "emotion"
}
},
Add The Babel Config
Create a new file .babelrc.js
in your project’s root directory and add the following lines:
module.exports = {
presets: [
[
'next/babel',
{
'preset-react': {
runtime: 'automatic',
importSource: '@emotion/react',
},
},
],
],
plugins: ['@emotion/babel-plugin', 'babel-plugin-macros'],
}
Customizing Twin
To be able to customize twin, you need to complete Step 4 above. You can find all the configuration options for twin.macro here.
Customizing Tailwind CSS
While it’s not compulsory, you might want to change the default style configuration that tailwind provides to suit your theme. To customize tailwind’s styles for your project, you’ll need to add a tailwind.config.js
file in your project’s root directory.
You can start with the empty config below:
module.exports = {
theme: {
extend: {
colors: {},
},
},
plugins: [],
}
Or, you can start with the full config, and tweak to your satisfaction. From your root folder run the following to get the full config:
npx tailwindcss-cli@latest init --full
Plugins
Twin supports many tailwind plugins, like @tailwindcss/typography and @tailwindcss/forms, but plugins that use the addVariant
function are not compatible.
Here’s the list of supported plugins