The Shim
The twind/shim
and twind/shim/server
modules provides seamless integration with existing Tailwind projects, making refactoring to Twind a breeze.
The shim works by detecting any Tailwind classes names used in your app and wrap them in tw
call under the hood. And since Twind supports all Tailwind utility classes, they will just work in Twind. The shim also supports all of Twind's extended syntaxes, variants, and rules without any additional configuration. And, it can be used along side the tw
function, which allows for gradual migration. Please see the Tailwind migration guide for more information.
Basic Usage
Simply include the twind/shim
module and watch the magic happen ✨
HTML:
<!DOCTYPE html>
<html lang="en" hidden>
<head>
<script type="module" src="https://cdn.skypack.dev/twind/shim"></script>
</head>
<body>
<main class="h-screen bg-purple-400 flex items-center justify-center">
<h1 class="font-bold text(center 5xl white sm:gray-800 md:pink-700)">This is Twind!</h1>
</main>
</body>
</html>
JavaScript:
import 'twind/shim'
// or
import { setup, disconnect } from 'twind/shim'
Prevent FOUC
To prevent FOUC (flash of unstyled content), set the hidden
attribute on the target element. twind/shim
will remove it once all styles have been generated.
<!DOCTYPE html>
<html lang="en" hidden>
<!-- ... -->
</html>
TIP
Internally twind/shim
uses twind/observe
, which may be useful for advanced use cases.
Support legacy browsers with UMD bundles
You may need to provide certain polyfills depending on your target browser.
<script defer src="https://unpkg.com/twind/twind.umd.js"></script>
<script defer src="https://unpkg.com/twind/observe/observe.umd.js"></script>
<script defer src="https://unpkg.com/twind/shim/shim.umd.js"></script>
The twind/shim
module utilizes the twind/observe module internally, but it provides its own setup function for customizing the used tw instance and setting the target node to be shimmed. It also provides a disconnect function to stop shimming/observing all nodes.
import { setup, disconnect } from 'twind/shim'
setup({
// node element to shim/observe (default: document.documentElement)
target: document.querySelector('main'),
// All other setup options are supported
})
// stop shimming/observing all nodes
disconnect()
tw
instance
Custom You can provide a <script type="twind-config">...</script>
within the document. The content must be valid JSON and all twind setup options (including hash) are supported.
<!DOCTYPE html>
<html lang="en" hidden>
<head>
<script type="module" src="https://cdn.skypack.dev/twind/shim"></script>
<script type="twind-config">
{
"hash": true
}
</script>
</head>
<body>
<main class="h-screen bg-purple-400 flex items-center justify-center">
<h1 class="text(center 5xl white sm:gray-800 md:pink-700)">
This is <span class="font-bold">Twind</span>!
</h1>
</main>
</body>
</html>
Alternatively the following works:
import { setup } from "https://cdn.skypack.dev/twind/shim"
setup({
target: document.body, // Default document.documentElement (eg html)
... // All other twind setup options are supported
})
It is possible to mix twind/shim
with tw
:
import 'twind/shim'
import { tw } from 'twind'
const styles = {
center: tw`flex items-center justify-center`,
}
document.body.innerHTML = `
<main class="h-screen bg-purple-400 ${styles.center}">
<h1 class="font-bold ${tw`text(center 5xl white sm:gray-800 md:pink-700)`}">
This is Twind!
</h1>
</main>
`
Server
If you wish to remove Twind's runtime overhead or you're interested in using Twind in a universal or "isomorphic" web app, twind/shim/server
exports the dedicated twind/shim/server.shim
function for performant processing of static HTML.
TIP
You'll find more details and examples in the ssr guide.
import { setup } from 'twind'
import { virtualSheet, getStyleTag, shim } from 'twind/shim/server'
const sheet = virtualSheet()
setup({ ...sharedOptions, sheet })
function ssr() {
// 1. Reset the sheet for a new rendering
sheet.reset()
// 2. Render the app to an html string and handle class attributes
const body = shim(renderTheApp())
// 3. Create the style tag with all generated CSS rules
const styleTag = getStyleTag(sheet)
// 4. Generate the response html
return `<!DOCTYPE html>
<html lang="en">
<head>${styleTag}</head>
<body>${body}</body>
</html>
`
}
In order to prevent harmful code injection on the web, a Content Security Policy (CSP) may be put in place. During server-side rendering, a cryptographic nonce (number used once) may be embedded when generating a page on demand:
// ... other code is the same as before ...
// Usage with webpack: https://webpack.js.org/guides/csp/
const styleTag = getStyleTag(sheet, { nonce: __webpack_nonce__ })
All Twind syntax features are supported within class attributes.
The shim
function also accepts an optional second argument that can be a custom tw
instance or an options object (including tw
instance).
import { create } from 'twind'
import { shim, virtualSheet, getStyleTag } from 'twind/shim/server'
const sheet = virtualSheet()
const { tw } = create({ ...sharedOptions, sheet })
sheet.reset()
const markup = shim(htmlString, {
tw, // defaults to default `tw` instance
})
const styleTag = getStyleTag(sheet)
Asynchronous SSR
❗ This is an experimental feature. Use with care and please report any issue you find. Consider using the synchronous API when ever possible due to the relatively expensive nature of the promise introspection API provided by V8. Async server side rendering is implemented using async_hooks. Callback-based APIs and event emitters may not work or need special handling.
import { setup } from 'twind'
import { asyncVirtualSheet, getStyleTagProperties, shim } from 'twind/server'
const sheet = asyncVirtualSheet()
setup({ ...sharedOptions, sheet })
async function ssr() {
// 1. Reset the sheet for a new rendering
sheet.reset()
// 2. Render the app to an html string and handle class attributes
const body = shim(await renderTheApp())
// 3. Create the style tag with all generated CSS rules
const styleTag = getStyleTag(sheet)
// 4. Generate the response html
return `<!DOCTYPE html>
<html lang="en">
<head>${styleTag}</head>
<body>${body}</body>
</html>
`
}