Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Design system: styles override using TailwindCSS

I am trying to create a Design System using ReactJS and TailwindCSS.

I created a default Button component with basic styling as follow:

import React from "react";
import classNames from "classnames";

const Button = React.forwardRef(
  ({ children, className = "", onClick }, ref) => {
    const buttonClasses = classNames(
      className,
      "w-24 py-3 bg-red-500 text-white font-bold rounded-full"
    );

    const commonProps = {
      className: buttonClasses,
      onClick,
      ref
    };

    return React.createElement(
      "button",
      { ...commonProps, type: "button" },
      children
    );
  }
);

export default Button;

I then use the Button in my page like:

import Button from "../src/components/Button";

export default function IndexPage() {
  return (
    <div>
      <Button onClick={() => console.log("TODO")}>Vanilla Button</Button>
      <div className="h-2" />
      <Button
        className="w-6 py-2 bg-blue-500 rounded-sm"
        onClick={() => console.log("TODO")}
      >
        Custom Button
      </Button>
    </div>
  );
}

This is what is displayed:

preview

Some attributes are overridden like the background-color but some aren't (the rest).

The reason is the classes provided by TailwindCSS are written in an order where bg-blue-500 is placed after bg-red-500, therefore overriding it. On the other hand, the other classes provided in the custom button are written before the classes on the base button, therefore not overriding the styles.

This behavior is happening with TailwindCSS but might occurs with any other styling approach as far as the class order can produce this scenario.

Do you have any workaround / solution to enable this kind of customisation?

Here is a full CodeSanbox if needed.

like image 582
Florian Ldt Avatar asked Mar 10 '21 21:03

Florian Ldt


People also ask

How do you override CSS Tailwind?

Due to the fact that the order of CSS class names in the class HTML attribute does not matter, the only way to override existing classes in an element is to remove all of the previous classes that clash with the new one.

Can I use normal CSS with Tailwind?

Tailwind at the most basic level is just css files. You can use both yours and Tailwind. You'll find that some of your styles may change though. The idea of Tailwind is to give you a base level of styling and tools to help you build something unique.


2 Answers

One approach is to extract classes from your component using Tailwind's @apply in your components layer.

/* main.css */

@layer components {
    .base-button {
        @apply w-24 py-3 bg-red-500 text-white font-bold rounded-full;
    }
}
// Button.js

const Button = React.forwardRef(({ children, className = "", onClick }, ref) => {
    const buttonClasses = classNames("base-button", className);

    // ...
);

This will extract the styles into the new base-button class, meaning they can easily be overwritten by the utility classes you pass to the Button component.

like image 50
juliomalves Avatar answered Oct 12 '22 19:10

juliomalves


Another approach to create reusable React components using Tailwind is as follows..

Read this gist

https://gist.github.com/RobinMalfait/490a0560a7cfde985d435ad93f8094c5

for an excellent example.

Avoid using className as a prop. Otherwise, it'd be difficult for you to know what state your component is in. If you want to add an extra class, you can easily extend.

You need a helper for combining classname strings conditionally. Robert, the writer of this gist, shared the helper function also with us:

export function classNames(...classes: (false | null | undefined | string)[]) {
  return classes.filter(Boolean).join(" ");
}
like image 35
cool Avatar answered Oct 12 '22 20:10

cool