⚡ Blazing fast full-featured Tailwind CSS + CSS in JS Compiler
MIT License
Full featured Tailwind compiler with CSS in JS support, with blazing fast build and runtime performance
You may have encountered some of these problems when using Tailwind CSS.
<MyComponent tw="bg-blue-500" />
<MyComponent bg-blue-500- >
<MyComponent bg-="blue-500" >
styled-system
<MyComponent css="line-height: 1.15;" /> and do not support Tailwind
`md:hover[text-xs font-normal]
with zero runtime dependencies from Arthietwstyled
contributorstw\`` helpers inside css, or as a simple CSS rule
@tailwind bg-blue-500 text-white-300`tw=
and css=
to inline Tailwind directly in the component, with full variable / logic supportnpm install --save twstyled @twstyled/babel-preset
or
yarn add twstyled @twstyled/babel-preset
Until our linaria enhancements to open the API to wrapper packages like this one are included in linaria upstream, please also add the follow resolutions to your package.json
file in your workspace root folder to point to our fork of linaria which is published on npm as @twstyled/linaria-babel-preset
// package.json
"resolutions": {
"@linaria/babel-preset": "npm:@twstyled/[email protected]",
"@linaria/preeval": "npm:@twstyled/[email protected]"
},
Create a babel.config.js
in your project
// babel.config.js
"use strict";
module.exports = {
presets: [
'@twstyled/babel-preset',
[
'next/babel',
{
'preset-react': {
runtime: 'automatic',
},
}
],
],
plugins: [],
}
In addition to the babel preset above, add a next.config.js
file to your project:
npm install --save @twstyled/next next-compose-plugins
or
yarn add @twstyled/next next-compose-plugins
const { withPlugins } = require('next-compose-plugins');
// next.config.js
module.exports = withPlugins(
[
require('@twstyled/next'),
],
{}
)
This plugin does not change the bundling but allows any CSS generated by Linaria to be included as CSS modules in each respective component; this is optimal for code-splitting and HTTP delivery of code
export const HeroHeading = (props) => (
<h1
tw="font-semibold text-3xl md:text-4xl lg:text-5xl not-italic"
{...props}
/>
)
This is the recommended approach if you want to share your components with other developers, as the string format is 100% compatible with any Tailwind implementation.
If you find these strings long and hard to read, you might prefer to have Tailwind utilities directly on the React classes. Every Tailwind class can be used as a (boolean) property directly on the React component, with a suffix of -
to keep
all Tailwind classes visually and logically distinct from your own properties. Negative properties should use the JSX Expression format below as it would otherwise be hard to see all these minus signs. Variants like hover:
, focus:
and screen hints are all supported using an array format and a suffix of --
again just to keep these visually distinct.
export const HeroHeading = (props) => (
<h1 font-semibold- text-3xl- md--={['text-4xl']} lg--={['text-5xl']} not-italic->
{...props}
/>
)
Every Tailwind class can be used as a prefix and a value property directly on the React component, with a suffix of -
to keep all Tailwind classes visually and logically distinct from your own properties.
export const HeroHeading = (props) => (
<h1 m-={-2} px-={3} font-={theme.fonts.headings} text-="3xl" md--:{['text-4xl']} lg--:{['text-5xl']} not-italic- >
{...props}
/>
)
Note how you can mix and match any of these formats together.
We recommend this option in all cases that you want to add a small number of style overrides for a given component. One advantage in the IDE and in code excerpts in blogs, is that you can quickly distinguish the type of style override from the actual value of style override. It is also useful if you are converting another library that has used styled system.
import { styled } from '@twstyled/core'
export const HeroHeading styled.h1`
@tailwind font-semibold text-3xl md:text-4xl lg:text-5xl not-italic;
line-height: 1.15;
import { styled } from '@twstyled/core'
export const HeroHeading styled.h1`
@tailwind font-semibold text-3xl md:text-4xl lg:text-5xl not-italic;
${mediaqueries.desktop} {
@tailwind p-1;
line-height: ${props => props.theme.largeSpacing && 1.15};
}
import { css } from '@twstyled/core'
export const styles = {
heading1: css`@tailwind font-semibold text-3xl md:text-4xl lg:text-5xl not-italic; /* standard CSS here */ line-height: 1.15;`
}
const HeroHeading = (props) => (
<h1 className={styles.heading1} />
)
import { tw } from '@twstyled/core'
const mixin = `font-semibold text-3xl`
const HeroHeading = (props) => (
<h1 tw={`${mixin} md:text-4xl lg:text-5xl not-italic`}
{...props}
/>
)
import { tw } from '@twstyled/core'
const special = `font-semibold text-3xl`
const HeroHeading = (props) => (
<h1 tw={`md:text-4xl lg:text-5xl ${props => props.isSpecial && special} not-italic`}
{...props}
/>
)
import { css } from '@linaria/css'
const HeroHeadingAdvanced = (props) => (
<h1
tw="font-semibold text-3xl md:text-4xl lg:text-5xl not-italic"
css={`
line-height: 1.15;
`}
{...props}
/>
)
Does not use the slower styles attributes behind the scenes but actually generates unique CSS classes and auto injects an import of the CSS file at build time for normal CSS handling by whatever bundler you use
import { css } from '@linaria/css'
const HeroHeadingAdvanced = (props) => (
<h1
tw="font-semibold text-3xl md:text-4xl lg:text-5xl not-italic"
css={`
line-height: 1.15;
`}
{...props}
/>
)
Converts to a twstyled component behind the scenes with tiny runtime to handle the dynamic property; automatically recognizes the scope of expressions and if needed adds a property to the generated class to handle locally scoped expressions and pre-evaluates globally scoped expressions.
const isLarge = true
const HeroHeadingAdvanced = (props) => {
const isItalic = true
return (<h1
tw=(`font-semibold ${isLarge ? "text-4xl" : "text-3xl"} ${isItalic ? "not-italic" : ""}`}
css={`
line-height: ${props => props.theme.linespacing};
`}
{...props}
/>)
}
is converted to the equivalent of
import { css, styled } from '@twstyled/core'
const TwCssH1 = styled.h1`
@tailwind font-semibold text-4xl ${props => props.$cssp1 ? "not-italic" : ""};
line-height: ${props => props.theme.linespacing};
`
const HeroHeadingAdvanced = (props) => (
const isItalic = true
<MyWrapperComponent>
<TwCssH1 $cssp1={isItalic} {...props}/>
</MyWrapperComponent>
)
class
instead of className
for compatibility with common Tailwind example kits <h1 class="font-semibold text-3xl md:text-4xl lg:text-5xl not-italic">Hello</h1>
tw=
JSX attribute and has not split out the import package, babel and webpack pluginstwstyled
is smaller (zero runtime in most cases), faster (no evaluation at runtime), and more feature complete (custom tw
and css
)css
attribute similar to emotion and styled-components but missing in Linaria, and to allow all the CSS generation to happen in the Babel plugin instead of reparsing each source file in a separate Webpack loader. We had to expose the API of Linaria a bit to accomplish this and have added our contributions to the core linaria packagetwstyled
and the actual source of the CSS used for each class; the vanilla implementation requires PostCSS purge processing which is less efficient as it uses string parsing and does not make use of the AST parsing that all bundlers include anywayThe MIT License (MIT)