/twin.macro

๐Ÿฆนโ€โ™‚๏ธ Twin blends the magic of Tailwind with the flexibility of css-in-js

Primary LanguageJavaScriptMIT LicenseMIT

twin logo

Twin blends the magic of Tailwind with the flexibility of css-in-js

Total Downloads Latest Release Discord


Use Twinโ€™s tw prop to add Tailwind classes onto jsx elements:

import 'twin.macro'

const Input = () => <input tw="border hover:border-black" />

Nest Twinโ€™s tw import within a css prop to add conditional styles:

import tw from 'twin.macro'

const Input = ({ hasHover }) => (
  <input css={[tw`border`, hasHover && tw`hover:border-black`]} />
)

Or mix sass styles with the css import:

import tw, { css } from 'twin.macro'

const hoverStyles = css`
  &:hover {
    border-color: black;
    ${tw`text-black`}
  }
`
const Input = ({ hasHover }) => (
  <input css={[tw`border`, hasHover && hoverStyles]} />
)

Styled Components

You can also use the tw import to create and style new components:

import tw from 'twin.macro'

const Input = tw.input`border hover:border-black`

And clone and style existing components:

const PurpleInput = tw(Input)`border-purple-500`

Switch to the styled import to add conditional styling:

import tw, { styled } from 'twin.macro'

const Input = styled.input(({ hasHover }) => [
  `color: purple;`,
  tw`border rounded`,
  hasHover && tw`hover:border-black`,
])
const Component = () => <Input hasHover />

Or use backticks to mix with sass styles:

import tw, { styled } from 'twin.macro'

const Input = styled.input`
  color: purple;
  ${tw`border rounded`}
  ${({ hasHover }) => hasHover && tw`hover:border-black`}
`
const Component = () => <Input hasHover />

How it works

When babel runs over your code, Twinโ€™s css and styled imports get swapped with the real imports from libraries like ๐Ÿ’… styledโ€‘components and ๐Ÿ‘ฉโ€๐ŸŽค emotion.

Twin offers import presets for both libraries or you can fully customise the imports.

When you use tw, Twin converts your classes into css objects, ready for passing to your chosen css-in-js library:

import tw from 'twin.macro'

tw`text-sm md:text-lg`

// โ†“ โ†“ โ†“ โ†“ โ†“ โ†“

{
  fontSize: '0.875rem',
  '@media (min-width: 768px)': {
    fontSize: '1.125rem',
  },
}

Features

๐ŸŽจ Style with all classes and variants available in Tailwind v1.9.4

๐Ÿน Adds no size to your build - Twin converts classes youโ€™ve used into css objects using Babel and then compiles away, leaving no runtime code

๐Ÿ›Ž Helpful suggestions for mistypings - Twin chimes in with class and variant values from your Tailwind config:

โœ• 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]

๐Ÿ–Œ๏ธ Use the theme import to add values from your tailwind config

import { theme, css } from 'twin.macro'

const Input = () => <input css={css({ color: theme`colors.purple.500` })} />

See more examples using the theme import โ†’

๐Ÿ’ฅ Add important to any class with a trailing bang!

tw`hidden!`
// โ†“ โ†“ โ†“ โ†“ โ†“ โ†“ โ†“ โ†“ โ†“
{ "display": "none !important" }

๐Ÿšฅ Over 40 variants to prefix on your classes - Unlike Tailwind, the prefixes are always available to add to your classes

  • Prefix with before: and after: to style pseudo-elements
  • Prefix with hocus: to style hover + focus at the same time
  • Style with extra group states like group-hocus: and group-active:
  • Style form field states with checked:, invalid: and required:
  • Stack variants for nested styles sm:hover:

Check out the full list of variants โ†’

๐Ÿฑ Apply variants to multiple classes at once with variant groups

import 'twin.macro'

const interactionStyles = () => (
  <div tw="hover:(text-black underline) focus:(text-blue-500 underline)" />
)

const mediaStyles = () => <div tw="sm:(w-4 mt-3) lg:(w-8 mt-6)" />

const pseudoElementStyles = () => (
  <div tw="before:(content block w-10 h-10 bg-black)" />
)

const stackedVariants = () => <div tw="sm:hover:(bg-black text-white)" />

const variantsInGroups = () => <div tw="sm:(bg-black hover:bg-white)">

Getting started

"Vanilla" React
Styled Components Demo Docs
Emotion Demo Docs
Create React App
Styled Components Demo Docs
Emotion Demo Docs
Gatsby
Styled Components Demo Docs
Emotion Demo Docs
Next.js
Styled Components Demo Docs
Emotion Demo Docs
Snowpack
Styled Components Repo
Emotion Repo
Vue
Emotion Demo (Experimental)

Plugins

You can use many Tailwind plugins with twin, like Tailwind UI and Custom forms but thereโ€™s no compatibility with other plugins that use the addVariant or addBase functions.

See list of supported plugins โ†’

TypeScript

Twin fully supports TypeScript projects and includes types for every import except the css and styled imports.

How to add the missing css and styled types โ†’

Community

Drop into our Discord server for announcements, help and styling chat.

Discord

Resources

Special thanks

This project stemmed from babel-plugin-tailwind-components so a big shout out goes to Brad Cornes for the amazing work he produced. Styling with tailwind.macro has been such a pleasure.