Use With
Setting up Twind for seamless integration in a React project.
- 🧭 Explore the examples
- 📓 Consult the API reference
- 📜 Read the changelog
This package does not have a dedicated standalone example. Instead, it is used in the following examples:
🤝 Compatibility
@twind/with-react | react |
---|---|
>=1.0.0 <2 | ^16.6.0 , 17.x , 18.x |
📦 Installation
@twind/core
and @twind/with-react
are available on npm and need to be installed together.
npm install @twind/core @twind/with-react
🙇 Usage
This package provides several modules that can be used to integrate Twind into your React project. The default export of @twind/with-react
is a function that can be used to setup the twind instance.
import install from '@twind/with-react'
import config from '../twind.config'
export default install(config)
The second parameter to install
determines if hashed class names are used. The default used process.env.NODE_ENV === 'production'
which might not work depending on your setup. In that case pass false
to always use non-hashed class names or something like import.meta.env.PROD
if you are using vite.
Besides the default module, the package also provides several subpath exports that can be used to generate server-side rendered styles:
inline
This module can be used to generate server-side rendered styles when using renderToString or renderToStaticMarkup.
import { renderToString } from 'react-dom/server'
import inline from '@twind/with-react/inline'
import tw from './twind'
import App from './App'
const html = inline(renderToString(<App />), tw)
pipeableStream
This module can be used to generate server-side rendered styles when using renderToPipeableStream.
This module fully supports Suspense and streaming of HTML with delayed content blocks popping in via inline <script>
tags later. During streaming, styles from each chunk will be collected and merged into the existing styles. If client-side Twind is used it will take over as usual and inject any further dynamic styles once client-side hydration is complete.
import { renderToPipeableStream } from 'react-dom/server'
import TwindStream from '@twind/with-react/pipeableStream'
import App from './App'
let didError = false
const stream = renderToPipeableStream(<App />, {
onShellReady() {
// The content above all Suspense boundaries is ready.
// If something errored before we started streaming, we set the error code appropriately.
res.statusCode = didError ? 500 : 200
res.setHeader('Content-type', 'text/html')
stream.pipe(new TwindStream()).pipe(res)
},
onShellError(error) {
// Something errored before we could complete the shell so we emit an alternative shell.
res.statusCode = 500
res.send('<!doctype html><p>Loading...</p><script src="clientrender.js"></script>')
},
onAllReady() {
// If you don't want streaming, use this instead of onShellReady.
// This will fire after the entire page content is ready.
// You can use this for crawlers or static generation.
// res.statusCode = didError ? 500 : 200;
// res.setHeader('Content-type', 'text/html');
// stream.pipe(new TwindStream()).pipe(res);
},
onError(err) {
didError = true
console.error(err)
},
})
readableStream
This module can be used to generate server-side rendered styles when using renderToReadableStream.
This module fully supports Suspense and streaming of HTML with delayed content blocks popping in via inline <script>
tags later. During streaming, styles from each chunk will be collected and merged into the existing styles. If client-side Twind is used it will take over as usual and inject any further dynamic styles once client-side hydration is complete.
import { renderToReadableStream } from 'react-dom/server'
import TwindStream from '@twind/with-react/readableStream'
import App from './App'
let controller = new AbortController()
let didError = false
try {
let stream = await renderToReadableStream(
<html>
<body>Success</body>
</html>,
{
signal: controller.signal,
onError(error) {
didError = true
console.error(error)
},
},
)
// This is to wait for all Suspense boundaries to be ready. You can uncomment
// this line if you want to buffer the entire HTML instead of streaming it.
// You can use this for crawlers or static generation:
// await stream.allReady;
return new Response(stream.pipeThrough(new TwindStream()), {
status: didError ? 500 : 200,
headers: { 'Content-Type': 'text/html' },
})
} catch (error) {
return new Response('<!doctype html><p>Loading...</p><script src="clientrender.js"></script>', {
status: 500,
headers: { 'Content-Type': 'text/html' },
})
}