DEV Community

Cover image for CSS variables for React developers
Matt Tarasov
Matt Tarasov

Posted on

CSS variables for React developers

Everyone has met a case when we need to customize React components for special design, right? Maybe you even have a UI-kit, but the designer thinks that this is a special case and you have to make this button bigger and brighter? So, I have a simple way to solve it. Say "No" to your designer. That's all. Bye.
It's a joke. I think the work of a software engineer is related to finding tradeoffs and sometimes we must do something a designer wants. Well, I want to talk about an easy way to customize components in React.

Naive way

Assume you have a button.
Image description

export const Button = ({ text, onClick }) => {
  return (
    <button className="button" onClick={onClick}>
      {text}
    </button>
  );
};
Enter fullscreen mode Exit fullscreen mode

With this css:

.button {
  padding: 12px 26px;
  background-color: skyblue;
  color: #ffffff;
  font-size: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

And now you need to increase padding and change color:
Image description

What is the simplest way to do it? Throw additional class name to props and use it:

export const Button = ({ text, onClick, className }) => {
  return (
    <button className={cn('button', className)} onClick={onClick}>
      {text}
    </button>
  );
};
Enter fullscreen mode Exit fullscreen mode

I've used this library to concatenate the className with the .button class

Well, we have a new class:

.secondary-button {
  padding: 20px 32px;
  color: #000000;
}
Enter fullscreen mode Exit fullscreen mode

Usage:

<Button text="Press me" className="secondary-button" />
Enter fullscreen mode Exit fullscreen mode

It's okay, but recently your colleague has changed main button:

export const Button = ({ text, additionalText, onClick, className }) => {
  return (
    <button className={cn("button", className)} onClick={onClick}>
      <span className="button__text">{text}</span>
      <span>{additionalText}</span>
    </button>
  );
};
Enter fullscreen mode Exit fullscreen mode

And css:

.button {
  background-color: skyblue;
  font-size: 1rem;
}
.button__text {
  display: inline-block;
  color: #ffffff;
  padding: 12px 26px;
}
Enter fullscreen mode Exit fullscreen mode

And what happened with your button? Your styles have broken because your selector isn't so strong as new for text. So, you have a bug.
Yes, you can just pass a new class only for text and everything will be working well, but how long?
I have a more safe and more powerful way to customize your components.

CSS variables

Everyone knows how to initialize css vars in :root (it's just an alias for <html> but more specific):

:root {
  --main-color: #ffffff;
}
Enter fullscreen mode Exit fullscreen mode

We also can use css vars within other selectors, like a class:

.some-class {
    --main-color: gray;
}
Enter fullscreen mode Exit fullscreen mode

And these variables also use inheritance like CSS properties.
So, are you thinking the same thing as me? We can use it to customize your component!

.button {
  --button-padding: 12px 26px;
  --button-color: #ffffff;

  padding: var(--button-padding);
  color: var(--button-color);
  background-color: skyblue;
  font-size: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

Well, look at the code above. We declare variables and use them in our first button version. Now, if you want to change padding or color, you have to write something like that:

.secondary-button {
  --button-padding: 20px 32px;
  --button-color: #000000;
}
Enter fullscreen mode Exit fullscreen mode

When someone wants to change inner css code of that button, you can be calm - everything will be working well:

.button {
  --button-padding: 12px 26px;
  --button-color: #ffffff;
  background-color: skyblue;
}

.button__text {
  display: inline-block;
  padding: var(--button-padding);
  color: var(--button-color);
}
Enter fullscreen mode Exit fullscreen mode

So, we write a low-coupled CSS code, with fewer bugs, and more reusability!

We can use css vars with containers, like this:

 export const Button = ({ text }) => {
  return (
    <button className="button">{text}</button>
  );
};
Enter fullscreen mode Exit fullscreen mode
.button {
  display: inline-block;
  /* Using default values var(--name, <default value>) */
  background-color: var(--button-bg-color, skyblue);
  color: var(--button-color, #ffffff);
}
Enter fullscreen mode Exit fullscreen mode

Now we can initialize variables --button-bg-color and --button-color in the Button's parent component and that's it!
Let's create a card class and wrap button in:

.card {
  --button-color: #000;
  --button-bg-color: peachpuff;
}
Enter fullscreen mode Exit fullscreen mode
    <div>
      <Button text="Default button"/>
      <div className="card">
        <Button text="Button into card"/>
      </div>      
    </div>
Enter fullscreen mode Exit fullscreen mode

Image description

Conclusion

CSS variables can help you to create reusable components and reduce bugs not only with React, but with other frameworks or without them! Anyway, I hope this article was interesting and you will start to use CSS variables in your work!

Top comments (0)