2

React Server Components (RSC) render on the server, leaving no JS for the browser to run.

My question is, can we access and manipulate the DOM in a RSC?

For instance, let's say we want to manipulate CSS variables based on data fetched in a RSC. We can accomplish that with document.documentElement.style.setProperty("--foo", foo);. Since document is not available server-side, we have to make the component a React Client Component (RCC). foo would be fetched in a RSC and passed as a prop into the RCC. However, it would be ideal if the server could handle the DOM manipulation as well, so that the HTML+CSS+JSON bundle served to the client (browser) by the RSC already contained the changes we know we want to make at build-time.

Is it possible to do the DOM manipulation server-side, in the RSC? If so, how?

Magnus
  • 6,791
  • 8
  • 53
  • 84

1 Answers1

3

No, you can't manipulate the DOM in React Server Components, because RSC don't render the "normal" DOM:

Of course you can modify what is rendered into the virtual DOM (just by using React as usual), but CSS variables are not part of the virtual DOM. A popular approach would be to use some CSS framework like tailwind.

Server Side Rendering (SSR)

You might be confusing RSC with Server Side Rendering (SSR), because RSC doesn't serve HTML+CSS+JSON to the client, as you said.

RSC doesn't do SSR in this sense, i.e. it doesn't render HTML (yet ?). What's sent over the network from the server to the client is something like this:

0:["$","div",null,{"className":"main","children":[["$","section",null,{ "children":[ ... ]}], ... ]}]

You still can use RSC and SSR together. E.g. you may render HTML at the server using other libraries or custom solutions, you may even build a server side DOM which can be used with the commonly known methods like document.getElementById, but RSC doesn't provide that.

E.g. you may consider using a framework like Next.js (at least version 13), which builds on React Server Components and provides SSR and SSG (Static Side Generation), but even with Next.js I doubt that you can manipulate CSS variables, but I'm not sure.

kca
  • 4,856
  • 1
  • 20
  • 41
  • Thanks kca, very helpful. I am actually using Next.js, and the site is statically generated (SSG). Build-time, the SCSS is compiled to CSS, but I have not found a way to make the JS that changes the CSS variables actually run build-time. Any suggestions there? I have not looked into Tailwind (currently using SCSS and styled-components). – Magnus Apr 01 '23 at 15:48
  • Had a quick look and didn't found a way in Next.js either. But I doubt it anyway. I can't imagine a use case where no other solution would work, e.g. for you example you can always add styles from global variables with SCSS. In the worst case you still could build parts of the CSS file dynamically "by hand". – kca Apr 01 '23 at 17:40
  • Hmmm, I might have explained the situation poorly. I already have several global CSS variables in the SCSS. I am fetching (`fetch()`) some theme (color) data in an RSC, and wanted to set the CSS variables based on that data. Since WebAPIs, like fetch(), cannot be run from SCSS, I have to be able to change the CSS variables with JS. Do you see what I mean? – Magnus Apr 01 '23 at 17:56
  • 1
    Sorry, my bad. I was thinking about [css-in-js](https://nextjs.org/docs/basic-features/built-in-css-support#css-in-js), not SCSS. I meant to change from using CSS variables to JS variables. i believe CSS itself (CSS variables) is never touched by next.js, and only evaluated in the browser. So only solution would be to build actual CSS files dynamically (manually, like `fs.writeFile('styles.css', data, ...)`), or use JS and build the styles dynamically. – kca Apr 02 '23 at 08:44
  • 1
    Ah, smart, I did not think of setting the CSS variables inline, straight into the element's `style` attribute (seems that works: https://www.freecodecamp.org/news/everything-you-need-to-know-about-css-variables-c74d922ea855/). That would overwrite the defaults set in the SCSS, which is what I wanted. What do you think? That approach should solve my problem, right? – Magnus Apr 02 '23 at 15:39
  • 1
    Oh, cool. I didn't know that was possible... Sounds plausible to me, if the HTML including the style attribute is completely pre-rendered (so that it gets evaluated right when the CSS is evaluated the first time). – kca Apr 02 '23 at 16:06
  • 1
    In case you and/or future readers find it interesting, I discovered the following in the Next docs: https://beta.nextjs.org/docs/api-reference/components/font#css-variables. Basically, the functions in the `next/font/google` library actually create a new stylesheet, then add class selectors containing the CSS variables. Example selector in a style sheet that was dynamically created by next: `.__variable_08423a {--font-roboto: "..."; }`. So, we could just follow the same approach and dynamically create a stylesheet with the CSS variables as classes, then add those to 's `className`. – Magnus Apr 02 '23 at 20:37
  • I see that might have been your suggestion above, @kca. It eluded me until now :). I ended up with the style attribute approach though, it was easier and worked well. – Magnus Apr 02 '23 at 21:08