Download this example using degit
npx degit https://github.com/ben-rogerson/twin.examples/next-emotion folder-name
From within the new folder, run npm install
, then npm run dev
to start the dev server.
Install Next.js
Choose "Yes" for the src/
directory option when prompted.
npx create-next-app@latest --javascript
Install the dependencies
npm install @emotion/react @emotion/styled
npm install -D twin.macro tailwindcss @emotion/babel-plugin babel-plugin-macros @babel/preset-react babel-loader babel-plugin-macros
Install with Yarn
Choose "Yes" for the src/
directory option when prompted.
yarn create next-app
Install the dependencies
yarn add @emotion/react @emotion/styled
yarn add -D twin.macro tailwindcss @emotion/babel-plugin babel-plugin-macros
Twin uses the same preflight base styles as Tailwind to smooth over cross-browser inconsistencies.
The GlobalStyles
import adds these base styles, some @keyframes for animations, and some global css variables.
You can import GlobalStyles
within a new file placed in styles/GlobalStyles.js
:
// src/styles/GlobalStyles.js
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
Then import the GlobalStyles file in src/pages/_app.js
:
// src/pages/_app.js
import GlobalStyles from '../styles/GlobalStyles'
const App = ({ Component, pageProps }) => (
<>
<GlobalStyles />
<Component {...pageProps} />
</>
)
export default App
Twin’s config can be added in a couple of different files.
a) Either in babel-plugin-macros.config.js
:
// babel-plugin-macros.config.js
module.exports = {
twin: {
preset: 'emotion',
},
}
b) Or in package.json
:
// package.json
"babelMacros": {
"twin": {
"preset": "emotion"
}
},
Note: The preset gets set to 'emotion' by default, so adding the config is only useful if you want to adjust Twin’s other options.
Create a new file either in the root or in a config
subfolder:
// withTwin.mjs
import babelPluginMacros from 'babel-plugin-macros'
import * as path from 'path'
import * as url from 'url'
// import babelPluginTwin from 'babel-plugin-twin'
const __dirname = url.fileURLToPath(new URL('.', import.meta.url))
// The folders containing files importing twin.macro
const includedDirs = [path.resolve(__dirname, 'src')]
/** @returns {import('next').NextConfig} */
export default function withTwin(
/** @type {import('next').NextConfig} */
nextConfig,
) {
return {
...nextConfig,
webpack(
/** @type {import('webpack').Configuration} */
config,
options,
) {
config.module = config.module || {}
config.module.rules = config.module.rules || []
config.module.rules.push({
test: /\.(jsx|js)$/,
include: includedDirs,
use: [
{
loader: 'babel-loader',
options: {
sourceMaps: options.dev,
presets: [
[
'@babel/preset-react',
{ runtime: 'automatic', importSource: '@emotion/react' },
],
],
plugins: [
// babelPluginTwin, // Optional
babelPluginMacros,
],
},
},
],
})
if (typeof nextConfig.webpack === 'function')
return nextConfig.webpack(config, options)
return config
},
}
}
Then in your next.config.mjs
, import and wrap the main export with withTwin(...)
:
// next.config.mjs
import withTwin from './withTwin.mjs'
/**
* @type {import('next').NextConfig}
*/
export default withTwin({
reactStrictMode: true,
})
Learn how to work with twin
- The prop styling guide - A must-read guide to level up on prop styling
- The styled component guide - A must-read guide on getting productive with styled-components
Learn more about emotion