bradlc / babel-plugin-tailwind-components

Use Tailwind with any CSS-in-JS library
MIT License
332 stars 25 forks source link
babel babel-plugin babel-plugins-macros css css-in-js tailwind tailwindcss

babel-plugin-tailwind-components npm Babel Macro

Use Tailwind with any CSS-in-JS library

Prerequisites

Before you start using babel-plugin-tailwind-components you will need to ensure that you have a Tailwind config file. You can grab the default config from the Tailwind repo.

Place the config file in your project root as tailwind.js. Alternatively you can specify a different filename in the plugin options.

Installation

There are two ways to use babel-plugin-tailwind-components. The recommended way is via babel-plugin-macros:

npm install --save-dev babel-plugin-macros tailwind.macro

Note: tailwind.macro is merely an alias for babel-plugin-tailwind-components/macro

Then add babel-plugin-macros to your babel config:

{
  "plugins": ["macros"]
}

Note: you will also need to install and enable @babel/plugin-syntax-object-rest-spread if you haven’t already

You can now use Tailwind classes with your preferred CSS-in-JS library by importing tailwind.macro:

import styled from 'styled-components'
import tw from 'tailwind.macro'

const Button = styled('button')`
  ${tw`font-mono text-sm text-red hover:text-blue`};
`

Alternatively, you can use the plugin without babel-plugin-macros:

npm install --save-dev babel-plugin-tailwind-components
// .babelrc
{
  "plugins": ["tailwind-components"]
}

When using this method the tw tag is available anywhere without an explicit import:

import styled from 'styled-components'

const Button = styled('button')`
  ${tw`font-mono text-sm text-red hover:text-blue`};
`

How it works

The babel plugin transforms the tagged template literal into a style object:

In

const foo = tw`text-red hover:text-green sm:text-blue`

Out

const foo = {
  color: '#e3342f',
  ':hover': {
    color: '#38c172'
  },
  '@media (min-width: 576px)': {
    color: '#3490dc'
  }
}

This style object format is compatible with most CSS-in-JS libraries, including styled-components.

Some libraries such as styled-jsx do not support this format, so when used inside a <style> element the tagged template literal is transformed into a CSS string instead:

In

<style jsx>{`
  .foo {
    ${tw`text-red hover:text-green sm:text-blue`};
  }
`}</style>

Out

<style jsx>{`
  .foo {
    color: #e3342f;

    &:hover {
      color: #38c172;
    }

    @media (min-width: 576px) {
      color: #3490dc;
    }
  }
`}</style>

Note: when using hover:*, focus:*, or media query (e.g. sm:*) class names the output is nested like above. You will need to use styled-jsx-plugin-postcss and postcss-nested to get this to work.

Options

config: path to your Tailwind config file. Defaults to "./tailwind.js"

format: CSS output format. "object", "string", or "auto" (default) – "auto" will cause the output to be an object except when inside a <style> element. See how it works for more info.

// babel-plugin-macros.config.js
module.exports = {
  tailwind: {
    config: './tailwind.js',
    format: 'auto'
  }
}

// or .babelrc
{
  "plugins": [
    [
      "tailwind-components", {
        "config": "./tailwind.js",
        "format": "auto"
      }
    ]
  ]
}

Examples

styled-components

import styled from 'styled-components'
import tw from 'tailwind.macro'

const Button = styled('button')`
  ${tw`font-mono text-sm text-red hover:text-blue`};
`

emotion

import styled from 'preact-emotion'
import { css } from 'emotion'
import tw from 'tailwind.macro'

const green = css(tw`text-green`)

const Button = styled('button')`
  ${tw`font-mono text-sm text-red hover:text-blue`};
`

const App = () => (
  <Button className={green} css={tw`uppercase`}>
    hello, world
  </Button>
)

Note: the css prop requires the use of babel-plugin-emotion

glamor

import { css } from 'glamor'
import tw from 'tailwind.macro'

const style = css(tw`font-mono text-sm text-red hover:text-blue`)

const App = () => <div {...style}>hello, world</div>

styled-jsx

import tw from 'tailwind.macro'

const App = () => (
  <div>
    <div className="foo">hello, world</div>
    <style jsx>{`
      .foo {
        ${tw`font-mono text-sm text-red hover:text-blue`};
      }
    `}</style>
  </div>
)

Note: when using hover:*, focus:*, or media query (e.g. sm:*) class names the output is nested. You will need to use styled-jsx-plugin-postcss and postcss-nested to get this to work.

Todo