Java Developer Learns React #1: Extending Styles With Styled Components

Recently I started to learn React (and frontend development in general) and it has been a really humbling experience. I think that the biggest reason for this is that I am used to writing traditional web applications and REST APIs with Spring and these applications use synchronous communication between the backend and the user / client. In React, most of the important things seem to be asynchronous which can be challenging if you like to try things out yourself before you read the user manual (old habits die hard).

To make matters worse, the last time I did frontend development was when doing server-side rendering was normal and we used jQuery for improving the usability of our web applications. If you have at least some experience from modern frontend development, you probably understand that I have no idea what I am doing. Nevertheless, I decided to start a new blog post series which identifies the problems I have faced and explains how I solved them. I hope this blog post series is useful and encourages other Java veterans to take a look at frontend development because it's quite rewarding.

Let's move on and take a look at today's problem.

I am not a React or frontend development expert. Don't follow the advice given in this blog post without doing your own due diligence.

The Problem

I wanted to modify a few CSS property values of an existing component because I had to create a new component that looks a bit different than the original component. Because the application was already using styled-components, I decided to extend the styles of the original component with styled-components. I opened the user manual and took a quick look at the section which describes how you can extend styles with styled-components, but I didn't really read it. Instead, I wrote this piece of code:

import styled from 'styled-components';
import './App.css';

const BoringDiv = () => <div>Lorem ipsum</div>;

const CoolDiv = styled(BoringDiv)`
  background-color: #292929;
  color: #fff;
`;

function App() {
  return (
    <>
      <BoringDiv></BoringDiv>
      <CoolDiv></CoolDiv>
    </>
  );
}

export default App;

I was expecting that the second div has a dark background and white text. Instead, I saw the following web page:

It was time to find out what went wrong.

What Went Wrong?

When I took a closer look at the DOM, I noticed that styled-components created a CSS rule which had the selector: .jvbqHK and added this rule to the header section, but didn't add the correct class attribute to the second div element. At this point, the DOM of the displayed web page looked as follows:

<html lang="en">
<head>
  <script type="module">
    import RefreshRuntime from "/@react-refresh"
    RefreshRuntime.injectIntoGlobalHook(window)
    window.$RefreshReg$ = () => {}
    window.$RefreshSig$ = () => (type) => type
    window.__vite_plugin_react_preamble_installed__ = true
  </script>

  <script type="module" src="/@vite/client"></script>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Java Developer Learns React #1 - Styled Components</title>
  <style type="text/css" data-vite-dev-id="App.css">
    #root {
      max-width: 1280px;
      margin: 0 auto;
      padding: 2rem;
      text-align: center;
    }
  </style>
  <style type="text/css" data-vite-dev-id="index.css">
    :root {
      font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
      line-height: 1.5;
      font-weight: 400;
      color: #000000;
      background-color: #ffffff;
    }
  </style>
  <style data-styled="active" data-styled-version="6.1.1">
    .jvbqHK { 
      background-color:#292929;
      color:#fff;
    }
  </style>
</head>
<body>
  <div id="root">
    <div>Lorem ipsum</div>
    <div>Lorem ipsum</div>
  </div>
  <script type="module" src="/src/main.tsx?t=1701016725735"></script>
</body>
</html>

It was time to talk to my former friend Google.

How I Solved the Problem

I was a bit surprised that my first Google search returned this StackOverflow answer which basically told me to RTFM. The user manual of styled-components has a section which explains how you can style any component. This section starts which the following sentence:

The styled method works perfectly on all of your own or any third-party component, as long as they attach the passed className prop to a DOM element.

After I made the required change to my React component, the source code of my App.tsx file looked as follows:

import styled from 'styled-components';
import './App.css';

const BoringDiv = ({ className }: { className?: string }) => (
  <div className={className}>Lorem ipsum</div>
);

const CoolDiv = styled(BoringDiv)`
  background-color: #292929;
  color: #fff;
`;

function App() {
  return (
    <>
      <BoringDiv></BoringDiv>
      <CoolDiv></CoolDiv>
    </>
  );
}

export default App;

After I reloaded my web page, I noticed that everything was working as expected:

Also, when I took a look at the DOM, I noticed that styled-components created a CSS rule which had the selector: .jvbqHK, added this rule to the header section, and added the correct class attribute to the second div element. After I had solved my problem, the DOM of the displayed web page looked as follows:

<html lang="en">
<head>
  <script type="module">
    import RefreshRuntime from "/@react-refresh"
    RefreshRuntime.injectIntoGlobalHook(window)
    window.$RefreshReg$ = () => {}
    window.$RefreshSig$ = () => (type) => type
    window.__vite_plugin_react_preamble_installed__ = true
  </script>

  <script type="module" src="/@vite/client"></script>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Java Developer Learns React #1 - Styled Components</title>
  <style type="text/css" data-vite-dev-id="App.css">
    #root {
      max-width: 1280px;
      margin: 0 auto;
      padding: 2rem;
      text-align: center;
    }
  </style>
  <style type="text/css" data-vite-dev-id="index.css">
    :root {
      font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
      line-height: 1.5;
      font-weight: 400;
      color: #000000;
      background-color: #ffffff;
    }
  </style>
  <style data-styled="active" data-styled-version="6.1.1">
    .jvbqHK {
      background-color:#292929;
      color:#fff;
    }
  </style>
</head>
<body>
  <div id="root">
    <div>Lorem ipsum</div>
    <div class="sc-bdfCDU jvbqHK">Lorem ipsum</div>
  </div>
  <script type="module" src="/src/main.tsx?t=1701015099161"></script>
</body>
</html>

So, did I learn anything?

Final Thoughts

Well, I guess the moral of this story is that if you aren't sure what you are doing, it's a good idea to read the user manual instead of skimming it.

P.S. You can get the sample code from Github.

0 comments… add one

Leave a Reply