React + SSR + NoScript + CSS in JS Fallbacks

Custom CSS for users with JS disabled.

July 10, 2018

What does that title even mean?

Assuming you have a site:

  • Using CSS in JS.
  • Using SSR (we're specifically using emotion, which is very similar to styled-components).
  • That you'd like to work for users with JS disabled.

Then it means this is the article you need to read.

The specific site I was solving this issue for was created with Gatsby, which has all of the above setup by default.

The Scenario

You have some images which you would like to initially be hidden. They will then fade in when the user scrolls to them.

This can be implemented like this:

The EnterAnimation class wraps children and shows them with a css animation when it is scrolled into view (using react-visibility-sensor to detect this).

The problem with this code is that when Gatsby extracts our CSS it will extract our hidden styles as the default. This means users with JS disabled will not be able to see any elements wrapped in this component.

To get around this problem we can create specific styles for users with JS disabled.

1. Add a no-js class on <html>.

We're using react-helmet to add attributes to our html. We can use the Helmet component to add a default no-js class to html. It's important that this is only added during SSR or else it will break styles for users with JS enabled. Checking the typeof window allows us to determine if we're doing SSR or not.

2. Remove no-js with a <script> in <head>.

We add a script in <head> to remove the no-js class (thanks to Paul Irish for this one-liner). Since it's a script it will only be removed for users who don't have JS disabled, and it won't run during SSR.

3. Add a no-js specific style.

To add a no-js specific style we'll use emotion.

We target the <html> element when it has the no-js class, then use & to target our specific component. This style will be included in SSR, but will only be enabled when the no-js class is present. For our JS users the class will be removed before the first render.

That's about all there is to it. Users without JS don't make up a large part of most audiences, but when the tooling makes it easy to support them why not make an attempt?

Dylan Vann
Software developer living in Toronto 🇨🇦 Thailand 🇹🇭.
Focused on Node | GraphQL | React | React Native.

You should receive an email with a confirmation link!
Join my Newsletter
I'll send you an email when I have something interesting to show.
Or follow me on Twitter for more stuff like this.


Tweet about this post and it will show here.