Skip to content

Instantly share code, notes, and snippets.

@zslabs
Forked from alexkuz/StylesContext.tsx
Created December 16, 2021 16:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zslabs/63350612a94de7d98a4fe7a13306b6cc to your computer and use it in GitHub Desktop.
Save zslabs/63350612a94de7d98a4fe7a13306b6cc to your computer and use it in GitHub Desktop.
Styled Components in Remix
import { renderToString } from "react-dom/server";
import { RemixServer } from "remix";
import type { EntryContext } from "remix";
import { ServerStyleSheet } from "styled-components";
import StylesContext from "./StylesContext";
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const sheet = new ServerStyleSheet();
// Render <body> and extract styles
let body = renderToString(
sheet.collectStyles(
<StylesContext.Provider value={{ styles: [], renderMode: 'body' }}>
<RemixServer context={remixContext} url={request.url} />
</StylesContext.Provider>
)
);
// Note: getStyleTags is not really suitable here, using getStyleElement instead
let styles = sheet.getStyleElement();
sheet.seal();
// Render <head> with styles extracted from body
let head = renderToString(
<StylesContext.Provider value={{ styles, renderMode: 'head' }}>
<RemixServer
context={remixContext}
url={request.url}
/>
</StylesContext.Provider>
);
let markup = `<!DOCTYPE html><html lang="en">${head}${body}</html>`;
responseHeaders.set("Content-Type", "text/html");
return new Response(markup, {
status: responseStatusCode,
headers: responseHeaders
});
}
...
function Document({
children,
title,
}: {
children: React.ReactNode;
title?: string;
}) {
let { styles, renderMode } = useContext(StylesContext);
let head = (
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
{title ? <title>{title}</title> : null}
<Meta />
<Links />
{styles}
</head>
);
let body = (
<body>
{children}
<ScrollRestoration />
<Scripts />
{process.env.NODE_ENV === 'development' && <LiveReload />}
</body>
);
switch (renderMode) {
case 'head':
return head;
case 'body':
return body;
default:
return (
<html lang="en">
{head}
{body}
</html>
);
}
}
...
import { createContext } from 'react';
import { ServerStyleSheet } from 'styled-components';
export default createContext<{
styles: React.ReactNode[];
renderMode: 'head' | 'body' | 'all';
}>({ styles: [], renderMode: 'all' });
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment