Getting Started
Migration
TODO with file diffs
from tailwindcss
from twind v0.16
Breaking Changes
-
the main package is @twind/core
-
@twind/core does not include any core utilities — use one or more of the presets
-
no more
twind/shim—install()(recommended) andsetup()automatically observe allclassattributes -
tw: only accepts a single string argumenttw('... class names ...')— for the v0.16 behavior usetxinstead -
css: only accepts a single CSS object or can be used as tagged template literal- no more
@global— you must use&for nested selectors (this follows the CSS Nesting Module) - no more string support for nested selectors — use
@applywithin the CSS object instead (see example on twind.run)
- no more
-
no more important suffix:
rule!->!rule -
no more
@screen sm-> use the tailwindcss syntax@media screen(sm) -
strict tailwindcss v3 compatibility
- no IE 11 fallbacks (color, box-shadow, ...)
- no more
font-*andtext-*shortcuts - no
border-trbutborder-[xytrbl]*still exists - no
bg-origin-* - droped IE 11 support
-
config theme section function has a changed signature
difftheme: { extend: { - fill: (theme) => ({ + fill: ({ theme }) => ({ gray: theme('colors.gray') }) } }
Notable Changes
See reference for a complete list of all available features until we have documentation for all of them.
-
API
- new function
installto simplify setup setupcan be called as many times as you want.- classes are returned in order they are applied by the browser - last one wins
tw:- the theme:
tw.theme(...) - the target sheet:
tw.target - allows to reset twind (start clean):
tw.clear() - allows to remove twind (remove the associated style element):
tw.destroy()
- the theme:
applyfinally works — styles are generated in order they are declaredshortcut— styles are generated as defined by twind — same as if they where used alone- with support for creating named shortcuts:
shortcut.PrimaryButton`bg-red-500 text-white`->PrimaryButton#<hash>
- with support for creating named shortcuts:
- new
cxfunction to create class names- grouped rules are ungrouped
- new
txfunction to create class names and inject styles — like usingtw(cx(...)) style— stitches like component definitions- creates readable class names like
style#1hvn013 style--variant-gray#1hvn013 style--size-sm#1hvn013 style--outlined-@sm-true#1hvn013
- with label:
style({ label: 'button', ... })button#p8xtwh button--color-orange#p8xtwh button--size-small#p8xtwh button--color-orange_outlined-true$0#p8xtwh
- creates readable class names like
- new function
-
- allow trailing dash before parentheses for utilities ->
border-(md:{2 black opacity-50 hover:dashed}} - shortcuts:
~to apply/merge utilities ->~(text(5xl,red-700),bg-red-100)- anonymous shortcuts:
~(!text-(3xl center) !underline italic focus:not-italic)- support comma-separated shortcuts — this prevents different classNames errors during hydration:
hover:~(!text-(3xl,center),!underline,italic,focus:not-italic)cx()converts space-separated to comma-separated
- support comma-separated shortcuts — this prevents different classNames errors during hydration:
- named shortcuts:
PrimaryButton~(bg-red-500 text-white)->PrimaryButton#<hash>shortcut()is a helper to simplify creation of shortcuts (works likeapply()in twind v0.16); it supports creating named shortcuts:shortcut.PrimaryButton`bg-red-500 text-white`->PrimaryButton#<hash>
- anonymous shortcuts:
- allow trailing dash before parentheses for utilities ->
-
config
-
presets are executed in order they are defined
-
presets can currently not contain other presets — a work-around may by to use
defineConfig()within the preset -
defineConfig()helper for typing -
preset merging:
preflight— last one winsthemeandtheme.extendare shallow merged — last one winsrules,variants, andignorelist— first one winsdarkMode,hashandstringifyare overridden if defined by the preset — last one wins
-
user config merging
preflight— applied lastthemeandtheme.extendare shallow merged — applied lastrules,variants, andignorelist— applied firstdarkMode,hashandstringifyare overridden if defined by the preset — applied first
-
darkMode can be selector string
{ darkMode: '.dark-mode &' }or{ darkMode: 'html[data-theme="dark"] &}` -
rules based on ideas from UnoCSS
js// defineConfig is optional but helps with type inference defineConfig({ rules: [ // Some rules ['hidden', { display: 'none' }], // Table Layout // .table-auto { table-layout: auto } // .table-fixed { table-layout: fixed } ['table-(auto|fixed)', 'tableLayout'], // Some aliases // shortcut to multiple utilities ['card', 'py-2 px-4 font-semibold rounded-lg shadow-md'], // dynamic shortcut ['card-', ({ $$ }) => `bg-${$$}-400 text-${$$}-100 py-2 px-4 rounded-lg`], // single utility alias — need to use `~(...)` as it would be otherwise recognized as a CSS property ['red', '~(text-red-100)'], // apply to multiple utilities ['btn-green', '@(bg-green-500 hover:bg-green-700 text-white)'], // dynamic apply ['btn-', ({ $$ }) => `@(bg-${$$}-400 text-${$$}-100 py-2 px-4 rounded-lg)`], ], })There are lots of things possible. See preset-tailwind/rules and preset-ext/rules for more examples.
-
ignorelist: can be used ignore certain rules
This following example matches class names from common libraries:
jsdefineConfig({ // emotion: `css-` // stitches: `c-` // styled-components: `sc-`and `-sc- // svelte: `svelte-` // vanilla-extract: sprinkles_ // goober: `go1234567890` // DO NOT IGNORE rules starting with `^[~#]`, `^css#`, or `^style[~#-]` — these may have been generated by `css()` or `style()`, or are hashed ignorelist: /^((css|s?c|svelte)-|(sprinkles)?_|go\d)|-sc-/, }) -
no implicit ordering within preflight
-
-
comments (single and multiline)
-
styles (the generated CSS rules) are sorted predictably and stable — no matter in which order the rules are injected
-
support
labelfor a more readable class names (https://emotion.sh/docs/labels) -
support theme(...) in property and arbitrary values
-
@apply finally works as expected
-
full support for color functions:
primary: ({ opacityVariable, opacityValue }) => ... -
new
@layerdirective following the Cascade Layers (CSS @layer) specThe following layer exist in the given order:
defaults,base,components,shortcuts,utilities,overridesjsimport { injectGlobal } from '@twind/core' injectGlobal` /* rules with base are not sorted */ h1 { @apply text-2xl; } h2 { @apply text-xl; } /* ... */ @layer components { .select2-dropdown { @apply rounded-b-lg shadow-md; } .select2-search { @apply border border-gray-300 rounded; } .select2-results__group { @apply text-lg font-bold text-gray-900; } /* ... */ } `