Styling React Components by Aditya Tyagi

4 Ways to Style React Components: A Beginner’s Guide

An introduction to statically and dynamically style React components

Styling React components is an essential part of building front-end applications. There are several ways in which we can achieve our desired styling in React. Not only it helps make the applications aesthetically pleasing, but also improves the overall user experience (UX). This is not a be-all guide to styling React components, but a starting point. My aim with this post will be to enlist few ways in which you can start adding styles to your monotonous React application.

The best way to learn is by doing. Hence, at the end of this post, I am also adding a code-sandbox so that you can practice all the examples covered here.

Inline Style

Adding inline styles to React is no different as compared to adding styles to normal HTML DOM elements. You use the same style attribute to add the inline styles. The only difference here is that:

  1. The value of the style attribute has to be an object
  2. The CSS properties follow camelCase

For example:

<label htmlFor="name" style={{paddingRight: '10px'}}>Name</label>

The style attribute will take an object with camelCased CSS properties. If you look closely, the object that we are passing is inside another { and }. The attribute does not accept a CSS string. It is more efficient and prevents XSS security holes.

Few examples depicting the camelCasing for CSS properties:

  1. padding-right –> paddingRight
  2. margin-left –> marginLeft
  3. background-image –> backgroundImage

The exception is aria-* and data-* attributes, which should be lowercased. For example, you can keep aria-label as aria-label.

An example of a styled object will be:

import React from "react";
import { render } from "react-dom";

// Main App component
const App = (props) => {

  // style object
  const lableStyle = {
    padding: 10, // will by default add 'px'
    marginRight: '1rem', // have to explicitly add the units if you want anything other than px
    backgroundColor: '#efefef',
    borderWidth: 2,
    borderStyle: 'solid',
    borderColor: '#000',
    borderRadius: 50,
    display: 'inline-block'
  }

  return (
    <div>
      <h1>Styling in React by Aditya Tyagi</h1>
      <form>
          {/* Passing style javascript object */}
          <label htmlFor="name" style={lableStyle}>Name</label>

          <input type="text" name="name"/>
        </form>
    </div>
  );
};

render(<App />, document.getElementById("root"));

This will result in:

An example of styling React components
Output for styled object

And the camelCase will be rendered just as any style renders in the DOM.

Output for the camelCase styling for a styled React component
Normal rendering of camelCase styling

Before we move to the next segment, I would like to point out that the styles are not auto-prefixed. Vendor prefixes, also known as CSS browser specific prefixes, should begin with a capital letter. There has been just one exception, and that is ms. You can explore here for more!

For example:

const styleObj = {
  WebkitTransition: 'all 4s ease', // checkout the capital 'W' here
  msTransition: 'all 4s ease', // 'ms' is lowercase
  MozTransition: 'all 4s ease',
  OTransition: 'all 4s ease',
  transition: 'all 4s ease'
};

An important thing to note here is that the React official docs recommends to NOT use the inline style method.

Some examples in the documentation use style for convenience, but using the style attribute as the primary means of styling elements is generally not recommended.

reactjs.org

Dynamic Inline Styles

Dynamic styling is an integral part of understanding the entire process of styling React components. React, even though recommends not to use the inline styling method, it does is on-board to use them to dynamically set styling on the DOM elements. By “dynamically”, I mean when there is state change. For this, you need to have a good grasp on how useState hook and state change works. If you want a refresher, you can check this out.

Let’s understand this with a simple example of changing the input border and background color when form is submitted with no input.

import React, { useState } from "react";
import { render } from "react-dom";

// Main App component
const App = (props) => {

  const [name, setName] = useState();
  const [isValid, setIsValid] = useState(true);

  // style object
  const lableStyle = {
    padding: 10, // will by default add 'px'
    marginRight: '1rem', // have to explicitly add the units if you want anything other than px
    backgroundColor: '#efefef',
    borderWidth: 2,
    borderStyle: 'solid',
    borderColor: '#000',
    borderRadius: 50,
    display: 'inline-block'
  }

  const nameChangeHandler = (e) => {
    setName(e.target.value)
  }

  const submitHandler = (e) => {
    e.preventDefault();
    if(!name) {
      setIsValid(false);
      return;
    }
  }

  return (
    <div>
      <h1>Styling in React by Aditya Tyagi</h1>
      <form onSubmit={submitHandler}>
          {/* Passing style javascript object */}
          <label htmlFor="name" style={lableStyle}>Name</label>

          {/* Conditionally set border for invalid input */}
          <input style={{border : !isValid ? '3px solid red' : ''}} value={name} type="text" name="name" onChange={nameChangeHandler}/>
          <button type="submit">Submit</button>
      </form>
    </div>
  );
};

render(<App />, document.getElementById("root"));

This will toggle the border color of the input with the state of isValid. The result will look something like:

Demo of dynamically adding styling to React component
Demo of dynamically adding styling to React component

Using Stylesheets and Class Names

The most sought after way to add styling to any DOM element in React is via classes. In React, we add classes using the className attribute on the DOM elements.

<h1 className="main-heading">Styling in React by Aditya Tyagi</h1>

To give CSS properties to the class main-heading we’ll use an external CSS stylesheet. We’ll then import that stylesheet in our App.js file or whichever file we want to use it in.

import "./style.css";

Yes, it is that easy. I have created a file (also available in the code-sandbox) style.css and imported it in App.js

/* style.css */

.main-heading {
  background-color: aqua;
}

And Voila! You can now style the main heading.

Styling React DOM components using external CSS stylesheets
Styling React DOM components using external CSS stylesheets

Setting CSS classes dynamically

The one rule we need to learn and respect is that the className will always be a string. This is besides our learning of adding CSS style object dynamically above. Combining the two and harnessing the power of template literals, we can set a class dynamically.

To understand this, we’ll follow the same example we used above about changing the border color to red on invalid submission.

/* style.css */

.main-heading {
  background-color: aqua;
}

.invalid {
  border: 2px solid red;
  background-color: #ffcfcf;
}

Using the invalid class dynamically on the input, we’ll witness a change in border and background color.

// in App.js

{/* Conditionally set border and background color for invalid input */}
    <input
        className={`${!isValid ? " invalid" : ""}`}
        value={name}
        type="text"
        name="name"
        onChange={nameChangeHandler}
    />

And the result will be:

Demo of dynamically setting class name
Demo of dynamically setting class name

Styled Components

The issue with the approaches above is that the styles that you import in one component DOES NOT scope to that only. It is accessible in the global scope and thus can lead to unforeseen issues, like classes over-writing each other. To resolve this and to scope the style to a particular component, I would like to introduce you “styled-components“. This library brought a significant change in styling React components and brought a different perspective to it!

Here, I will try to give you a formal introduction to this package but if you want to dive deeper, feel free to explore!

The styled-components package helps you to build React components that have certain styles attached to it and these styles affect only them. The styles attached to these components are scoped.

Install the package using:

npm install --save styled-components

The code-sandbox at the end of the blog already has this package installed. So, please feel free to practice there.

To understand the working of styled-components, let’s try to style the submit button in our form.

// in App.js

// import
import styled from 'styled-components';

// Creating the styled button using the "styled" object imported from "styled-components"
// It will return a styled React component

const StyledButton = styled.button`
 display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: #000;
  color: white;
  border: 2px solid white;
`;

The first thing is to import styled from styled-components library. This will help us to create styled React components. We use tagged template literal syntax to create styled components. The tagged template literal is not specific to React or this library. It is a JavaScript feature.

The imported styled object has several methods. Here we are accessing the button method. Here, the method names are nothing but the DOM elements. The styled object have methods for all HTML elements.

Example:

Various methods present on styled object
Various methods present on styled object

Anything passed between the back-ticks after the method, will be passed to that method, just in a special way. Please go through this to learn more about it.

For :focus and other pseudo-classes, you can use the & symbol. You do not have to use the selectors like button.

const StyledButton = styled.button`
 display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: #000;
  color: white;
  border: 2px solid white;

  &:hover {
    opacity: 0.5;
    cursor: pointer;
  }
`;

By default, the component that is returned by styled will apply all the props that you pass to it. So, you can still add onClick prop and others like it on the StyledButton component.

Using it in App.js form:

<StyledButton type="submit">Submit</StyledButton>
Demo of styled component button with hover
Demo of styled component button with hover

If you now inspect the button in dev tools, you’ll see 2 classes. The classes might be different for you as the styled-components library generate these classes for you. It guarantees that these class names are unique and hence resolves the scoping issue.

Classes add by styled-components
Classes add by styled-components

Dynamically Update Styled Components

As we already know that the component returned by the styled object will also have all the props passed to it. Therefore, using this, we can now dynamically update styled component.

To understand this with an example, we’ll again go back to our invalid form and border changing example and try to update the input field with styled component.

We’ll be passing an invalid prop to the StyledInput component and use that for dynamic styling. The passed prop will then be accessible on the props which is in the arrow function.

<StyledInput
    invalid={!isValid} // prop
    className={`${!isValid ? " invalid" : ""}`}
    value={name}
    type="text"
    name="name"
    onChange={nameChangeHandler}
></StyledInput>

And the corresponding StyledInput will be something like:

const StyledInput = styled.input`
  border: 1px solid ${(props) => (props.invalid ? "red" : "black")};
  background-color: ${(props) => (props.invalid ? "#ffcfcf" : "")};
`;

As a result, we can now dynamically update styling.

Demo of dynamically updating style using styled components
Demo of dynamically updating style using styled components

Media Queries and Styled Components

Adding media queries to styled-components is pretty straightforward. An example, should be enough.

const StyledButton = styled.button`
  display: inline-block;
  border-radius: 3px;
  padding: 0.5rem 0;
  margin: 0.5rem 1rem;
  width: 11rem;
  background: #000;
  color: white;
  border: 2px solid white;

  &:hover {
    opacity: 0.5;
    cursor: pointer;
  }
  @media screen and (min-width: 768px) {
    background: pink;
    color: black;
    border: 1px solid black;
  }
`;

And this will update the button styling for view-ports greater than 768px.

An example of Media queries with styled components
An example of Media queries with styled components

CSS Modules

You can take your CSS and styling work in React applications to the next level with CSS Modules. It is not mandatory, but I like the separation of CSS from my HTML. It’s easy to read and work with. CSS Modules help solve the scoping problem of CSS classes while still using CSS external stylesheets.

NOTE: This will work only with apps that are configured to use this, because there are certain code transformations that happen behind the scenes. The code-sandbox that I have presented you with, is already configured.

Here, we’ll be styling our submit button as an example. For this, we’ll move all the current button styling to style.css file and then import the file in a special way, using a special syntax.

// import
import styles from "./style.module.css";

The file name should ALWAYS follow this naming convention to work properly.

<fileName>.module.css

So, in our case, the file name is style.module.css

All the classes, like .button we have added to the stylesheet will be present on the object styles present in the import statement.

You can use it like this:

<button type="submit" className={styles.button}>Submit</button>

This will produce the same results as above.

Button with CSS Modules
Button with CSS Modules

The way it generates the class name ensures it is unique throughout the project so that it never encounters the scoping problem. Here, we access the classes as properties.

Dynamic Styles with CSS Modules

To dynamically set CSS classes, we will again use template literal. We will follow the same example we have been using. We’ll update the styling of the input on invalid form submission.

className={`${!isValid ? styles.invalid : ""}`}

Bonus: A playground

The example followed in this blog post has been around a form. To explore best practices around working with forms in React, you can refer this guide.

This wraps up a detailed account of 4 different ways of styling React components, both static and dynamic. I hope you could follow and found it helpful.

1 comment / Add your comment below

Leave a Reply

Your email address will not be published. Required fields are marked *