Help us understand the problem. What is going on with this article?

Writing Scalable and Modular CSS with React

More than 3 years have passed since last update.

React is a cool technology, and a tool I love to work with. React does some stuff amazingly good, but at the same time ignores a lot of other things, and that's where we developers have to take action to fix those issues.

One problem i've noticed when it came to React, is its styling scalability and ugly code that is generated when we're styling react components. The problem i've seen around is that, much of the styling code placed in React components is using conditional statements and inner react states to add styles/replace, but somehow they don't work well when it comes to reusability of those components and scalability.

Lets take a simple example, of styling a simple component using my personal style-guide that has derived from OOCSS and SMACSS.

// Normal styled component 
const Button = ({children}) => {
  return (<button className="button">{props.children}</button>);
}

Now the above code is a simple styled button, but how do we use that specific component to generate a bigger amount of styles for the buttons. Let say we have a primary button, and a Secondary button and so on?

The primitive way would be to create different components with different styling. But that is bad for scalability of the application, and also increases code pollution.

A way to solve this would be to use the properties in React, and as we know, by default if the properties are not assigned in the component, they return false, and if they're assigned even without any actual values, they return true, so we can use this to our advantage.

// Pattern styled component 
const Button = ({primary, secondary, tertiary, children}) => {
  const baseClass = "button";
  const primaryClass = "primary-button";
  const secondaryButton = "secondary-button";
  const tertiaryButton = "tertiary-button";

  if (primary) baseClass + " " + primaryClass;
  if (secondary) baseClass + " " + secondaryButton;
  if (tertiary) baseClass + " " + tertiaryButton;
  return (<button className={baseClass}>{props.children}</button>);
}

And when we invoke that component we can simply use the following form:

// Normal styled component 
const exampleOne = ({children}) => {
  return (<Button primary>Hello World</Button>);
}
const exampleTwo = ({children}) => {
  return (<Button secondary>Hello World</Button>);
}
const exampleThree = ({children}) => {
  return (<Button tertiary>Hello World</Button>);
}

But wait a moment, that component is a bit ugly, if i start adding if's and what not, the component will grow really big.

For that we have a saviour, and its called npm i classnames --save

With that in mind lets rewrite the component to look better:

// Final styled component 
const Button = ({primary, secondary, tertiary, children}) => {
  const defaultClassName = classnames("button", {
    "primary-button": primary,
    "secondary-button": secondary,
    "tertiary-button": tertiary
  });
  return (<button className={defaultClassName}>{props.children}</button>);
}

See, easy right? And looks amazing, and also you can use this pattern in a lot more ways.

But we aren't finished yet. To make this work, you also have to structure the CSS/SCSS to fit this need, so you don't have any style conflicts.

.button {
  // default button styles here
}

.primary-button {
  // Primary button styles here
}

.secondary-button {
 // Secondary button styles here
}

.tertiary-button {
 // Tertiary button styles here
}

Every style will overwrite the default styles if needed, but still they have a specific job.

This pattern can be applied to any component you would like, it also can be used to dynamically apply styles based on component state, for example:

// Normal styled component 
const Button = ({primary, secondary, tertiary, children}, state) => {
  const defaultClassName = classnames("button", {
    "primary-button": primary,
    "secondary-button": secondary,
    "tertiary-button": tertiary,
    "disabled": state.isDisabled,
    "loading": state.isLoading
  });
  return (<button className={defaultClassName}>{props.children}</button>);
}

This is something coming from my experience building high scalability UI in React. Let me know your opinions and suggestions.

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away