Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Last active August 4, 2022 06:46
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ryanflorence/b7f1653404b350483909609e435a8a2d to your computer and use it in GitHub Desktop.
Save ryanflorence/b7f1653404b350483909609e435a8a2d to your computer and use it in GitHub Desktop.
Remix + Styled Components
import ReactDOMServer from "react-dom/server";
import type { EntryContext } from "@remix-run/core";
import Remix from "@remix-run/react/server";
import { renderToString } from "react-dom/server";
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();
// first pass to collect styles
renderToString(
sheet.collectStyles(
<StylesContext.Provider value={null}>
<Remix context={remixContext} url={request.url} />
</StylesContext.Provider>
)
);
// get the styles
let styles = sheet.getStyleTags();
sheet.seal();
// second time with the styles on context
let markup = ReactDOMServer.renderToString(
<StylesContext.Provider value={styles}>
<Remix context={remixContext} url={request.url} />
</StylesContext.Provider>
);
return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: {
...Object.fromEntries(responseHeaders),
"Content-Type": "text/html"
}
});
}
import { Meta, Scripts } from "@remix-run/react";
import { useContext } from "react";
import StylesContext from "./stylesContext";
export default function Root() {
// get styles from context
let styles = useContext(StylesContext);
return (
<html>
<head>
<Meta />
{styles}
</head>
<body>
<Scripts />
</body>
</html>
);
}
import { createContext } from "react";
export default createContext<null | string>(null);
@elpatronaco
Copy link

While on dev mode it's only styling on the first request right? Am I doing something wrong?

@davidfloegel
Copy link

same for me

@FernandoRogelin
Copy link

Same error here

@MilanKrupa
Copy link

MilanKrupa commented Jan 9, 2022

I faced the same issue. As a workaround you can do the following:

  1. Set up styled-components as shown in the Remix documentation.

  2. Inside your root.tsx in the <head/> tag instead of {styles} put the following:
    {styles !== null && (<style dangerouslySetInnerHTML={{ __html:</style>${styles}<style> }} /> )}

Please note that this is not a safe solution! According to React documentation:

In general, setting HTML from code is risky because it’s easy to inadvertently expose your users to a cross-site scripting (XSS) attack.

That is why I do not recommend using it in production. It can significantly speed up development process though (you don't have to restart dev enviroment each time you make a change). I guess we have to wait until the creators of Remix provide us with dedicated solution.

@ram2104
Copy link

ram2104 commented Jun 10, 2022

Thanks, @MilanKrupa for sharing the workaround. For the first time, the pages of my app were rendering with proper styles because of SSR I believe but after client-side hydration, the styles were going away.

I was able to fix the issue by avoiding "dangerouslySetInnerHTML" because that is prone to XSS. here us my snippet of code from root. tsx: styles !== null && <style>{styles}</style>}

Thanks to @ryanflorence for sharing the original integration snippet.

@martinmckenna
Copy link

martinmckenna commented Aug 4, 2022

why not just inject the style tags at the end of the <head /> like so?

    const markupWithStyles = markup.replace(
      /<\s*\/\s*head\s*>/gm,
      `${styleTags}</head>`
    );

    return new Response("<!DOCTYPE html>" + markupWithStyles, {
      status: responseStatusCode,
      headers: responseHeaders,
    });

edit: nvm this solution still causes the loss of styles upon rehydration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment