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()

Custom tw instance

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>
  `
}