Twin blends the magic of Tailwind with the flexibility of css-in-js
Demo twin on CodeSandbox β
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 StyledInput = styled.input(({ hasBorder }) => [
`color: black;`,
hasBorder && tw`border-purple-500`,
])
const Input = () => <StyledInput hasBorder />
Or use backticks to mix with sass styles:
import tw, { styled } from 'twin.macro'
const StyledInput = styled.input`
color: black;
${({ hasBorder }) => hasBorder && tw`border-purple-500`}
`
const Input = () => <StyledInput hasBorder />
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 these 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 v2
πΉ 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!
<div tw="hidden!" />
// β β β β β β β β β
<div css={{ "display": "none !important" }} />
Add !important to multiple classes with bracket groups:
<div tw="(hidden ml-auto)!" />
// β β β β β β β β β
<div css={{ "display": "none !important", "marginLeft": "auto !important" }} />
π₯ Over 40 variants to prefix on your classes - Unlike Tailwind, the prefixes are always available to add to your classes
- Prefix with
before:
andafter:
to style pseudo-elements - Prefix with
hocus:
to style hover + focus at the same time - Style with extra group states like
group-hocus:
andgroup-active:
- Style form field states with
checked:
,invalid:
andrequired:
- Stack up variants whenever you need them
sm:hover:first:bg-black
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 groupsInGroups = () => <div tw="sm:(bg-black hover:(bg-white w-10))">
π‘ Integrates with the official tailwind vscode plugin - Avoid having to look up your classes with auto-completions straight from your tailwind config - See setup instructions β
Get started
Take a look at these examples to get started:
React
π styled-components π©βπ€ emotion
Preact
π styled-components π₯ goober
Create React App
π styled-components π©βπ€ emotion
Gatsby
π styled-components π©βπ€ emotion
Next.js
π styled-components π©βπ€ emotion
Snowpack
π styled-components π styled-components (TypeScript) π©βπ€ emotion
Storybook
Monorepo component library
π styled-components (TypeScript)
Laravel
π styled-components (TypeScript)
Plugins
You can use many Tailwind plugins with twin, like tailwindcss-typography and @tailwindcss/forms but thereβs no compatibility with plugins that use the addVariant
function.
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.
Resources
- Create advanced themes with css variables
- Sync your screen breakpoints with javascript
- Twin vscode snippits for easier imports
- Use the official vscode intellisense extension with twin
- Tailwind class cheat sheet
- "Why I Love Tailwind" by Max Stoiber
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.