prism-react-renderer
prism-react-renderer copied to clipboard
Expose CSS Variables for SSR to avoid FOUC
Fixes #149 .
This solution is inspired by the article that @jpdriver linked in the above issue. There are no breaking changes. The solution works as follow:
- Modify the given
themeprop to replace hard-coded properties with CSS variable placeholders (e.g.backgroundColor: '#000000'-->backgroundColor: var(--backgroundColor)). - On the server, inject a script tag that defines those CSS variables (e.g.
root.style.setProperty('--backgroundColor', '#000000)). These CSS variables will only be used for the first render. - On the client, after the first render, override those CSS variables to use the theme stored in React state.
It's a little confusing, but I think it's the simplest solution to solve this tricky problem. I'm very much open to suggestions or even rewriting the entire PR. It will probably help your understanding if you read this PR commit by commit.
TODO
- [x] ~Add Docusaurus example to README~ https://github.com/facebook/docusaurus/pull/7867
- [x] Add Next.js example to README
this is really exciting @narinluangrath -- thank you so much for picking this up! one thing i would say from a demo / example perspective and to help us all get on the same page with the review, we should probably add a Docusaurus-based example.
this work was called out as something we specifically need to add to help those folks out (and in turn Formidable's own Docusaurus sites!)
would be great if we can all see what that would look like in practice
this is really exciting @narinluangrath -- thank you so much for picking this up! one thing i would say from a demo / example perspective and to help us all get on the same page with the review, we should probably add a Docusaurus-based example.
this work was called out as something we specifically need to add to help those folks out (and in turn Formidable's own Docusaurus sites!)
would be great if we can all see what that would look like in practice
@jpdriver https://github.com/facebook/docusaurus/pull/7867
@slorber
Was wondering: why not always using CSS variables in the first place, instead of just for the 1st render? I don't like too much the idea of having 2 different paths for 1st render vs others, the UX could easily get out of sync over time.
So we actually use CSS variables for both the 1st render and the subsequent client side renders. The different between the first render and the second is where the CSS variables are defined. In the first render (assuming you're using generateScriptForSSR) they are defined in a <script /> that you've injected into the <body />. For the subsequent renders, those CSS variables are overwritten in the style attribute of top level Prism HTML element (<pre />, in the screenshot below).

Doesn't it make sense to create a unique "prism-css-variable" theme and create themes that just set the appropriate CSS variables.
Instead of using inline styles everywhere, it would be possible to use classes + set CSS variables once at the top? It might also give a lighter DOM structure.
Let me think about this and get back to you. Just to be clear, this PR uses inline styles and CSS variables (you don't have to pick one or the other).