I'll explain what is twin.macro and I'll show you all of the features provided by twin.macro.
What is twin.macro?
It's a library wich basically converts your TailwindCSS classes into CSS objects and shares them with emotion or styled-components to give you the power of writing with Styled Components.
Features
First, we need to know that twin.macro works with emotion or styled-component.
Support
twin.macro it's available for Vanilla JavaScript, React.js (CRA), Gatsby, and Next.js. Vue.js it's only an experimental version.
Pluggins
For the moment, twin.macro accepts certain plugins like:
Prop to JSX Elements
You can pass the tw
prop into JSX elements, a good way if you have an element without a lot of classes.
/** @jsx jsx **/
import { jsx } from '@emotion/core';
import 'twin.macro';
export default function App() {
return (
<h1 tw="text-2xl text-blue-500 font-bold">Hello world</h1>
);
}
In emotion it's very important that you import the JSX to your component, without this your classes appear like [object object] and obviously we don't want that.
Nesting tw
with css
prop
In this case, you can pass de css
prop to a JSX Element in order to create conditional styles.
In the example, we have a variable called isBold and basically in the css
prop check if the isBold is true. If it's true then we will have an element with font-bold
class.
/** @jsx jsx **/
import { jsx } from '@emotion/core';
import tw from 'twin.macro';
export default function App() {
const isBold = true;
return (
<h1 css={[tw`text-3xl text-blue-500`, isBold && tw`font-bold`]}>Hello world</h1>
);
}
Mixing SASS styles with the css
import
With the css
import, we can mix SASS style with our TailwindCSS classes.
/** @jsx jsx **/
import { jsx } from '@emotion/core';
import tw, { css } from 'twin.macro';
export default function App() {
const myCustomStyles = css`
${tw`font-bold`}
&:hover {
font-weight: 500;
${tw`text-black`}
}
`;
return (
<h1 css={[tw`text-3xl text-blue-500`, myCustomStyles]}>Hello world</h1>
);
}
Styled Components
With the tw
import we can create a Styled Component, good if you have elements that you repeat a lot.
import React from 'react';
import tw from 'twin.macro';
const MyButton = tw.button`border-2 border-blue-500 px-4 py-2`;
export default function App() {
return (
<MyButton>Hello World!</MyButton>
);
}
And maybe, you want to have a "base" style for a Styled Component, you can Clone and Edit an existing Styled Component.
import React, { Fragment } from 'react';
import tw from 'twin.macro';
const MyButton = tw.button`border-2 border-blue-500 px-4 py-2`;
const MyPrimaryButton = tw(MyButton)`text-white bg-blue-500`; // Cloned Styled Component
export default function App() {
return (
<Fragment>
<MyButton>Hello World!</MyButton>
<MyPrimaryButton>My Second Hello World!</MyPrimaryButton>
</Fragment>
);
}
Styled Component - Conditional Styles
Maybe you need a conditional style, with styled
import we can do it.
import React from 'react';
import tw, { styled } from 'twin.macro';
const MyButton = styled.button(({isBold, isPrimary}) => [
tw`mt-5 ml-5 border-2 border-blue-500 px-4 py-2`,
// Ternary
isBold ? tw`font-bold` : tw`font-semibold`,
// Conditional Style
isPrimary && tw`text-white bg-blue-500`
]);
export default function App() {
return (
<MyButton isPrimary>Hello World!</MyButton>
);
}
In this Styled Component, you can create conditionals styles, passing props to the function in this case we have two "isBold" and "isPrimary". We can use the ternary operator to apply certain classes or styles depending on what we need.
Variant Groups
One of twin.macro's new enhancements is the ability to group classes, which I really loved.
Maybe you're working in the Responsive web desing or in multiple classes or styles for the hover pseudo-class.
So, twin.macro allows you to group multiple classes, for example you have the following classes in your Styled Component:
<h1 tw="text-blue-500 bg-blue-500 border-2 border-blue-500 hover:text-blue-900 hover:bg-blue-900 hover:border-blue-500" >Hello World</h1>
Maybe you don't want to re-write hover:
prefix to all the classes, now in twin.macro you can do the following:
<h1 tw="text-blue-500 bg-blue-500 hover:(text-blue-900 bg-blue-900)">Hello World</h1>
Do you see it? You only need a single hover:() to add multiple styles that will react to the pseudo-element.
See all variants to Prefix your Classes
Theme
If you have a custom tailwind.config.js file, you can use our custom values of this file with the theme
import available in twin.macro.
twin.macro only uses the
theme
andplugins
variables available in tailwind.config.js
Example
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
electric: '#db00ff',
ribbon: '#0047ff'
}
}
},
plugins: []
}
So, we have our tailwind.config.js with custom variables, to use it, we need to import the theme
in our application.
// React.js App Example
/** @jsx jsx **/
import { jsx } from '@emotion/core';
import tw, { css, theme } from 'twin.macro'
const App = () => (
<div
css={[
tw`flex flex-col items-center justify-center h-screen`,
css({
// Grab values from your config with the theme import
background: `linear-gradient(
${theme`colors.electric`},
${theme`colors.ribbon`}
)`
})
]}
>
<h1>Hello World!</h1>
</div>
)
export default App;
So, as you can see we create a custom linear-gradient using the custom colors that we add to tailwind.config.js. ${theme`color.electric`}
In some cases you need to import and use the jsx import for emotion to use the prop CSS in JSX elements.
/** @jsx jsx **/ import { jsx } from '@emotion/core';
You don't see the error?
Maybe you don't remember the TailwindCSS class that you want, maybe looks like ml-45 or ml-73?
twin.macro has a helpful suggestion if you write a wrong class twin.macro will show you something like that:
✕ ml-7 was not found
Try one of these classes:
ml-0 [0] / ml-1 [0.25rem] / ml-2 [0.5rem] / ml-3 [0.75rem] / ml-4 [1rem] / ml-5 [1.25rem] / ml-6 [1.5rem]
ml-8 [2rem] / ml-10 [2.5rem] / ml-12 [3rem] / ml-16 [4rem] / ml-20 [5rem] / ml-24 [6rem] / ml-32 [8rem]
ml-40 [10rem] / ml-48 [12rem] / ml-56 [14rem] / ml-64 [16rem] / ml-auto [auto] / ml-px [1px]
In order to help you remember and write the correct class you need.
Top comments (4)
Nice article.
I've been trying to get twin macro to work with my Next JS App, I can't seem to figure it out. Is there a resource you could recommend. Meanwhile I've used this before with CRA.
You can read the following post:
github.com/ben-rogerson/twin.macro...
you might want to check out my template here, it's using nextjs, i'm using rtk query for the state managment.
github.com/okeken/nextjs-rtk-query
Hi. Very good writeup. Can twin.macro be used with lit-element?