CSS-in-JS is so back

Issue #298.June 17, 2024.2 Minute read.
Bytes

Today’s issue: What Astro learned from the secret Applebee’s training facility, a new use case for WebContainers, and a type-friendly way to spend your Friday night.

Welcome to #298.


Eyeballs logo

The Main Thing

Wormtail holding up tiny Voldemort from Harry Potter

The dark lord of CSS shall rise again

CSS-in-JS is so back

If you’ve been hanging out on the React dark web lately, you might have noticed a surprising trend – new CSS-in-JS libraries are popping up like it’s 2017 all over again.

Panda came out last summer, Meta open-sourced StyleX in December, Material UI released PigmentCSS last month, and Restyle just launched a few weeks ago.

Why the sudden resurgence? As I see it, there are two potential causes:

  1. Time is a flat circle
  2. New features in React

This isn’t the time or place for a deep dive on Nietzsche, so let’s discuss the second reason.

styled-components and other CSS-in-JS libraries became popular in the late 2010s, because they helped solve problems like style encapsulation and rendering styles on demand.

But this approach never played well with server rendering, often forcing you to jump through hoops like rendering your app twice on the server to make things work. As server rendering became more ubiquitous, developers steadily moved away from CSS-in-JS libraries in favor of other approaches.

But React server components and other new React features could change all that. For example, React 19 comes with new in how React handles <script> and <style> tags inside of components. This includes support for style hoisting, where React moves these tags into the head of the document based on their precedence attribute – all while supporting concurrent rendering on the client and streaming rendering on the server.

Restyle utilizes this functionality to load styles on demand in a way that just works on the server – so you can author your styles in JavaScript and send them over the wire as CSS.

Bottom Line: Last week, I walked into a vintage store and saw two teenagers arguing over the exact pair of chunky Etnies skate shoes that I proudly wore in middle school back in 2003. Yes, this made me feel old, but it also provided a perfect metaphor for React styling solutions – just wait a few years and whatever you used to like will probably become cool again.

        

speedcurve logo

Our Friends
(With Benefits)

Renaissance-style painting of woman looking at a phone

When you push some new features and the site won’t load

Catch performance regressions *before* they happen with SpeedCurve

Your site was super fast when you built it – but now it’s 6 months later, and that thing feels slower than a 4-hour Scorsese movie.

Next time, use SpeedCurve.

Their regression monitoring platform was created by a team of web performance pioneers to help you catch performance regressions before they happen.

Here’s how it works:

  1. Create performance budgets by setting thresholds for metrics you care about, like Core Web Vitals

  2. Integrate SpeedCurve with your CI/CD process to send you alerts or even break the build when the performance budget is violated

  3. Get all the diagnostics you need to find and fix the problems, when there’s an issue

Check out the free trial – and see why developers at Airbnb, Shopify, and many more really love it.


Pop Quiz logo

Pop Quiz

Sponsored by React Universe Conf

Callstack’s massive React & React Native conference is back this September with speakers like Evan Bacon, Monica Restrepo, Kent C. Dodds, and more. Check out early-bird pricing before it’s gone!

What gets logged?

function getPort(url) {
  const { port } = new URL(url);

  if(port === '80') {
    console.log("You're using the default port");
  }

  if(port === '443') {
    console.log("You're using the default secure port");
  }

  console.log(`You are running on port "${port}"`);
}

getPort(`http://example.com:80`)
getPort(`http://example.com:8080`)
getPort(`https://example.com:443`)
getPort(`https://example.com:3000`)

Cool Bits logo

Cool Bits

  1. In response to last issue’s Spot the Bug challenge, Brad Frost shared his article with us on Enforcing accessibility best practices with automatically-generated IDs.

  2. StackBlitz just unlocked a new use case for WebContainers: in-browser code execution for AI. This lets you execute, interpret, and refactor AI-generated code directly in the browser – with zero compute costs, zero latency, and zero VMs 🙏. [sponsored]

  3. There was a lot of drama last week about some React 19 changes to suspense and sibling pre-rendering, which seems to be largely resolved now. Praise TKDodo for saving our souls, yet again. If you missed it, here’s a summary from the man himself.

  4. Related, here’s how React 19 almost made the internet slower.

  5. TypeScriptToLua lets you write a project in TypeScript and transpile it to Lua. Just in case you’re looking for a crazy way to spend your Friday night.

  6. If you’ve ever dealt with an application that sends email, you’ve probably ignored learning about “SPF, DKIM, and DMARC” before. But since it’s no longer 2018 and the job market is actually competitive, here’s A Simple Guide to them.

  7. The Node team just released a new guide on Using Node.js’s test runner.

  8. CarbonQA provides high-quality QA services for your dev team. Their US-based testers work directly with your tools and will break your app repeatedly, so you never have to waste eng time on QA testing again. [sponsored]

  9. DGM.js is an infinite canvas library for smart shapes, real-time collaboration, hand-drawn styles. Think of it as a slightly less ugly more visually appealing Excalidraw.

  10. Fred K. Schott gave a 20-minute talk about the future of Astro and their work on “server islands” – which is the name of the secret location where I did all my training and orientation to become an Applebee’s waiter in high school.


Pop Quiz logo

Pop Quiz: Answer

Sponsored by React Universe Conf

What gets logged?

function getPort(url) {
  const { port } = new URL(url);

  if(port === '80') {
    console.log("You're using the default port");
  }

  if(port === '443') {
    console.log("You're using the default secure port");
  }

  console.log(`You are running on port "${port}"`);
}

getPort(`http://example.com:80`) // You are running on port ""
getPort(`http://example.com:8080`) // You are running on port "8080"
getPort(`https://example.com:443`) // You are running on port ""
getPort(`https://example.com:3000`) // You are running on port "3000"

The URL constructor function in JavaScript strips the default port even if it’s explicitly provided. Since port 80 is the default for http and port 443 is the default for https, the port is stripped from the URL resulting in an empty string. File this one away under JavaScript quirks that you probably don’t need to know, but could save future you hours of debugging.