Creating a common component library with CSS and SASS in React.
Tags: react, css
Published: 2019-10-30 21:47:04

There are more than enough options when deciding a toolset for building the common components in React. In this post, we are going to explore how to build common components with CSS and SASS and what kind of benefits and pitfalls there are.

From the all options, CSS files with [SASS](https://sass-lang.com/) addition has the lowest learning curve because these tools are used very similarly to a normal web page development. CSS files are very simple to import to React component and SASS gives some nice optional additions like variables and calculations which ease up more complex work.


## Setup

Setting up a CSS and SASS files to React project also very simple to do whether you are using Create React App or Webpack.

### Optional: Create a separate component library package

In case you are doing a separate package, you need to take care of both the package and the consumer sides. On a separate package, you can either distribute the CSS files as is and let the consumer do the transpiling or transpile the CSS files already on the package and distribute the result. I would suggest using the first choice since it gives more options to the consumer.

Doing transpiling on the consumer side makes package creation easy. You need to ensure that both variable and styles files are included in the package when moved to the artifactory. The files need to be just copied to the build directory and then on the consumer side referred like Javascript files:

```
import '@packagename/styles.css';
import '@packagename/variables.css';
```

If you want to do transpiling on the package side, you need to use your transpiler to create bundle style files. In case you are not using any bundler, I can suggest [Rollup](https://rollupjs.org/guide/en/). Otherwise, find the needed plugin/extension. To transpile the sass files, you can use [PostCss](https://github.com/egoist/rollup-plugin-postcss) rollup plugin that includes the styles inside the javascript files or creates separate CSS bundle files.

See example from repository [css-sass-rollup](https://github.com/ARautio/common-components-post/tree/master/packages/css-sass-rollup) and [sass-consumer](https://github.com/ARautio/common-components-post/tree/master/packages/sass-consumer).

### Create React App

If you are using Create React App you just need to install node-sass.

> npm install node-sass --save-dev

### Webpack

With webpack, the project needs a bit more configuration but setup is still very straight forward. Besides node-sass we need to install sass-loader, css-loader and style-loader.

> npm install node-sass sass-loader css-loader style-loader --save-dev

And then add all these to webpack.config.js

```
{
  test: /\.s[ac]ss$/i,
  use: ['style-loader', 'css-loader', 'sass-loader'],
}
```

### Parcel

[Parcel](https://parceljs.org/) handles both css and scss out of the box so you can start using them immediately without any configuration.

## Importing css and scss files

Importing the scss / css files inside a component happens like any other import in javascript. For example:

```javascript
import React from 'react'
import './style.scss'

const Box = () => (
   <div className="box">Box</div>
 )
export default Box
```

Once CSS file is imported, the content becomes available everywhere in the application (as long as it is imported). This means you don't necessary have to import the css file where you are using the classes. In a sense this gives a huge flexibility regarding how to handle the styles.  In a most extreme way you could import the css in a root JS file but I wouldn't suggest to do that.

## How to structure the common components with css

Since CSS has a global namespace, it's very likely that at some point in a project two classnames overlap or otherwise cause issues. To mitigate these this, it's advisable to use some naming convention to separate the component from each other ensure that all unique components have their own classnames. One of the most popular is [Block, Element,Modifier (BEM)](https://css-tricks.com/bem-101/).

The idea with naming convention is the use same way to determine the classnames so that they are easy to recognize and reuse. Instead of making the classes be applicable for one use case like:

```scss
.disabled_btn {
 border: 1px solid $color-border;
 border-radius: $space-s;
  background-color: $color-disabled;
  color: $color-light-text;
```

We would split the classes to be more generic and only add the necessary additions to more specific classes.


```scss
.btn {
  border: 1px solid $color-border;
  border-radius: $space-s;
  color: $color-dark-text;
}

.btn--disabled {
  background-color: $color-disabled;
  color: $color-light-text;
} 

```

## How to use classnames properly

This structure is very extendable and easy to use in different situations. We can use the css straight away:

```javascript

const CoolButton = ({ children, classNames, onClick }) => (
  <button className={classNames} onClick={onClick}>{children}<button>
)
```

or build a layer inside the component to handle classnames:

```javascript
import classnames from 'classnames'

const Button = ({children, disabled, onClick}) => (
  <button 
    className={classnames('btn',{ 'btn--disabled': disabled })}
    onClick={onClick}
  >
   {children}
  <button>
)

```

Note that in the latter example we are using [classnames](https://github.com/JedWatson/classnames) which helps out handle multiple class names tremendously.
While both ways of using class names are correct, I would strongly recommend using the second one where class names are handled inside the common component and only properties are exposed outside.

Having properties handle the class name changes limits the amount of available different ways the component can be manipulated, which simplifies the testing and ensuring that the changes won't break the design. 

Unfortunately, there is no way to extend the common component when only exposing the properties so if you need an extendable component, it could be done by creating a base component with className property and build the used component without className property.

For example if we extend the previous example the used component would look like:

```javascript
const Button = ({children, disabled, onClick}) => (
  <CoolButton 
    classNames={classnames('btn',{ 'btn--disabled': disabled })}
    onClick={onClick}
  >
   {children}
  <button>
)
```

This way we get both extendability and limited amount of options. 

## Using variables from SCSS

Consistent design most often has a defined color palette and standardized spacing. With CSS and SCSS this can be done with variables added to be imported in the root javascript file (for example App.js)

The scss file could look like:

```css

$background-Color: global #fff,
$primary1Color: global #408bbd,
$primary2Color: global #408bbd,
$secondary1Color: global none,
$secondary2Color: global #61b0e7,
...
$sSpacing: global '3px',
$mSpacing: global '6px',
$lSpacing: global '12px',
...

```

And to be used other scss files like:


```css

.btn--primary {
   background-color: $primary1Color;
   padding: $sSpacing;
}

```

If the theme file starts to get bigger, there are also way to use SASS functions and mixins to help out keeping a better structure and easing the usages. 

The benefit of using the global variables comes yet again from restrictions. When you limit yourself to use theme variables when defining colors or spacing, you also make sure that there is an easy overview what different option are used. This makes things yet again easier to test and ensure that everything works as they should. 


## Benefits and drawbacks of using CSS and SASS while creating the common components

As we have seen, CSS and SASS bring a powerful way to do common components/design without adding too much complexity. The component library would be easy to understand even by the developers who haven't done a lot with React and it most likely would be understandable for the people who mainly use only HTML + CSS.

The biggest advantage to use CSS and SASS is the convertibility. Since the styles are separated from the React component, the style can be reused between the frameworks. This gives a huge advantage if the same design is shared between an application that is not done only with React.

There are a couple of drawbacks too. Handling the class names manually creates a lot of possibilities to create an unmaintainable mess. The naming convention will help but this needs be managed constantly (or to have proper Eslint rules).

In my opinion, this toolset is still relevant and should be seen as an equal option when deciding what to use in a project.

Repository [css-sass](https://github.com/ARautio/common-components-post/tree/master/packages/css-sass) has an example how to use this in a project.

*This is a second post from the series __Speed up development by creating a common Component library__. The later posts will cover up the other options to build the common component library and how to document the library.*