Styling Components in React

Styling Components in React

by | 4 min read
Published:
Updated:

As I mentioned in my previous posts there are quite a few ways to create components in React.js. As it happens there are also quite a few ways to style components as well.

The great thing about React is you can create components in isolation. However, if you are not careful you could end up with conflicting CSS styles.

CSS has come a long way especially with the ability to use Sass and Less to create computed styles but you still need to be careful to make sure you aren’t affecting something else in your application. For anyone who has had to use !important you know what I am talking about.

So let’s have a look at the different ways to style components.

Adding standard classes

There are a few cases where you are going to need to use standard css classes. As we saw in my previous post, class is a protected keyword in JSX. To deal with this we have to use className instead.

function PrimaryButton({ children }) {
  return <button className="button is-primary">{children}</button>
}

The attribute className works in exactly the same was as class does in normal HTML and you can use it to reference styles from an external style sheet.

This is particularly useful if you are converting an existing project to use React or you are referencing class names from an external package. You can import * as stylesheets directly into your components with import ./Button.css.

Inline CSS

Another way of styling React components is with inline CSS. This is probably my least favourite way of styling components in react but it does solve the issue of having conflicting styles as the styles are scoped to the component.

The style that you provide to the component is written as a javascript object and uses camel case instead of the normal css casing. e.g. border-colour becomes borderColor.

const buttonStyle = {
  backgroundColor: '#00d1b2',
  borderColor: 'transparent',
  color: '#fff',
  cursor: 'pointer',
  justifyContent: 'center',
  paddingBottom: '.5em',
  paddingLeft: '1em',
  paddingRight: '1em',
  paddingTop: '.5em',
  textAlign: 'center',
  whiteSpace: 'nowrap',
}

function PrimaryButton({ children }) {
  return <button style={buttonStyle}>{children}</button>
}

It is easy to get caught out if you forget to camel case when of your styles with this method.

CSS Modules

Another way to scope styles to the component is to use CSS modules. With CSS modules you can write your styles in a standard style sheet.

button.css

.button {
  cursor: pointer;
  justify-content: center;
  padding-bottom: 0.5em;
  padding-left: 1em;
  padding-right: 1em;
  padding-top: 0.5em;
  text-align: center;
  white-space: nowrap;
}

.primary {
  background-color: #00d1b2;
  border-color: transparent;
  color: #fff;
}

button.jsx

import * as styles from './button.css'

function PrimaryButton({ children }) {
  return (
    <button className={[styles.button, styles.primary].join(' ')}>
      {children}
    </button>
  )
}

When you are using multiple classes that are imported in this way you can’t just reference them in the string as they are variables. One option is to use the join method shown in the example above.

Another option is to use template literals:

import * as styles from './button.css'

function PrimaryButton({children}) {
  return <button className=`${styles.button} ${styles.primary}`>{children}</button>
}

You can also use the classnames package which is a bit more natural to write.

import * as styles from './button.css'
import classnames from 'classnames'

function PrimaryButton({ children }) {
  return (
    <button className={classnames(styles.button, styles.primary)}>
      {children}
    </button>
  )
}

One of the great things with classnames is you can also do conditional classes. This is particularly useful if you want to programatically have styles apply.

import * as styles from './button.css'
import classnames from 'classnames';

function PrimaryButton({children}) {
  return <button className={classnames(styles.button,{styles.primary : true})}>{children}</button>
}

Styled Components

The last method I am going to share today is using the styled-components library. Styled components allow you to add css styles that are locally scoped without the need to create separate css files.

import styled from 'styled-components'

const Button = styled.button`
  cursor: pointer;
  justify-content: center;
  padding-bottom: 0.5em;
  padding-left: 1em;
  padding-right: 1em;
  padding-top: 0.5em;
  text-align: center;
  white-space: nowrap;

  background-color: ${props => props.primary && '#00d1b2'};
  border-color: ${props => props.primary && 'transparent'};
  color: ${props => props.primary && '#fff'};
`

<Button primary>Click Me</Button>

You can also create styled components from other components.

import styled from 'styled-components'

const Button = styled.button`
  cursor: pointer;
  justify-content: center;
  padding-bottom: 0.5em;
  padding-left: 1em;
  padding-right: 1em;
  padding-top: 0.5em;
  text-align: center;
  white-space: nowrap;
`

const PrimaryButton = styled(Button)`
  background-color: #00d1b2;
  border-color: transparent
  color: #fff
`

<PrimaryButton>Click Me</PrimaryButton>

Final thoughts

There are many ways to style components in React. Which one you use will depend on the project you are working on. If you are using an external stylesheet from a library such as Bootstrap or Bulma then simple CSS classes is probably best.

Of course if you have additional styling you want to use on top you could always use styled-components as well.


🙏 Was this helpful? If you want to say thanks, I love coffee ☕️ , any support is appreciated.


ALSO ON ALEXHYETT.COM

Idempotency - What it is and How to Implement it

Idempotency - What it is and How to Implement it

  • 22 September 2023
When designing an API it is easy to think about the happy path of our applications but if you want to build a robust application and keep…
5 Design Patterns That Are ACTUALLY Used By Developers

5 Design Patterns That Are ACTUALLY Used By Developers

  • 08 September 2023
High-level programming languages have been around since the 1950s and since then programmers worldwide have been using code to solve all…
Domain-Driven Design: Simple Explanation

Domain-Driven Design: Simple Explanation

  • 28 April 2023
When you are trying to build complex software it is important that everyone is on the same page. Even though most of us prefer to work alone…
Monolithic vs Microservice Architecture - Which Should You Use?

Monolithic vs Microservice Architecture - Which Should You Use?

  • 17 March 2023
If you are starting to build a new application or you are working on an existing one you may be wondering whether you should be building a…
Hexagonal Architecture: What Is It and Why Do You Need It?

Hexagonal Architecture: What Is It and Why Do You Need It?

  • 17 February 2023
We all do our best to try and write clean code that is going to be easy to maintain in the future. As time goes on and the application gets…
Snake Case vs Camel Case vs Pascal Case vs Kebab Case

Snake Case vs Camel Case vs Pascal Case vs Kebab Case

  • 06 February 2023
Coming up with names for things when writing software is hard. You need to come up with a few words that neatly describe everything you have…
What is CRUD? CRUD Operations in APIs

What is CRUD? CRUD Operations in APIs

  • 01 February 2023
90% of software that you use every day are what we call CRUD applications. Most of the time we are using them without even realising it…
Why Developers Should Embrace No-Code Solutions

Why Developers Should Embrace No-Code Solutions

  • 09 January 2023
The best line of code is the one you didn’t have to write. As developers, we love writing code. At the end of the day, it is what we are…