Computer scienceFrontendReactReact Components

Styling components

8 minutes read

Styling is a crucial aspect of creating React components. You can apply style in React in several ways, each having its unique benefits and drawbacks. In this topic, you will learn about three primary methods to style React components: inline styles, imported styles, and CSS Modules. Additionally, you'll understand what dynamic styles are and how they enhance the creation of interactive user interfaces.

Inline styles

Inline styling involves defining styles directly within the React component. It allows you to write almost any CSS properties inside JSX. To do so, you need to create a style object and pass it into the style property.

Below is a React component as an example:

// src/App.jsx

import React from "react"

function App() {
  const wrapperStyles = {
    textAlign: 'center',
    color: '#92A8D1',
  }

  const picStyles = {
    width: '300px',
    borderRadius: '10px'
  }

  return (
    <div style={wrapperStyles}>
      <h2>It's never too late to be whoever you want to be.</h2>
      <img style={picStyles} src="https://shorturl.at/EORT4"  />
    </div>
  )
}

export default App

In this example, we created two objects: wrapperStyles and picStyles. Each object contains specific CSS properties. To activate them, pass the first object into the div's style property, and embed the second one into the img tag.

In React, write CSS property names in camelCase; for example, borderRadius, marginTop, fontSize, etc. React interprets a hyphen (-) as a minus sign, which means writing a property in normal CSS style will produce an error. Note, the same syntax applies to pure JS too.

Note the use of curly braces to wrap our objects. This is because JSX follows an HTML-like syntax, yet objects are a JS feature. The use of curly braces allows JSX to interpret it as a JavaScript expression and utilize its value. Without the curly braces, styles objects would be processed as a literal string instead of the defined object.

You could also directly write the styles inside the tags without defining style objects. In this situation, use two curly braces: the first one enables JS within HTML, and the second one constructs an object. Separate key-value pairs with a comma. Here's an example:

import React from 'react';

function App() {
   return (
      <div style={{textAlign: 'center', color: '#92A8D1'}}>
         <h2>It's never too late to be whoever you want to be.</h2>
         <img style={{ width: '300px', borderRadius: '10px' }} src="https://shorturl.at/EORT4" />
      </div>
   );
}

export default App;

Either approach produces the same results:

inline styles

Imported styles

Inline styles are straightforward and easy to use, but they lack some CSS features like pseudo-classes and media queries. As your components expand and the styles grow larger, the code becomes more complex to read and comprehend. In this scenario, separating CSS from JS is advisable.

With this method, you can create a CSS file for each component and declare its styles there. For example, we can generate an App.css file and transfer all the styles to that file:

/* src/App.css */

.wrapper {
  text-align: center;
  color: #92A8D1
}

.pic {
  width: 300px;
  border-radius: 10px
}

In the App.jsx file, you just need to import this file and React will pick up the styles:

import React from 'react';
import './App.css';

function App() {
   return (
      <div className="wrapper">
         <h2>It's never too late to be whoever you want to be</h2>
         <img className="pic" src="https://shorturl.at/EORT4" />
      </div>
   );
}

export default App;

The App.css file contains two class names, wrapper and pic. To use them inside our component, you should use the className attribute and assign our CSS names. You might be curious why it is className, not the class that is used in HTML.

In JavaScript, the class is a reserved keyword used for class declarations. So, when JSX was being developed as a syntax extension for JavaScript, using class to define HTML classes could have caused parsing conflicts and syntax errors.

To prevent these problems, JSX uses className to define HTML classes. When React compiles JSX into regular JavaScript, className is converted back to class in the resulting HTML.

As previously stated, we recommend creating a separate CSS file for each component. This practice keeps our code clean and well-organized. Suppose we have three components: header, app, and user. This is how our folder structure could look like: folder structure

There is a component folder inside the src directory. Each of the three components has its own CSS file, so we don't need to store all the styles in one place. As for the index.css file, it's typically used for global styles that apply to the entire app.

CSS modules

CSS Modules provide a way to ensure that styles are locally scoped to a component and do not impact other parts of the application. These are CSS files in which all class names and animation names are scoped locally by default. This means that two components can have identical CSS names with different style rules, and they will not affect each other.

This is a very useful feature, as you no longer need to create unique class names or follow CSS naming methods like BEM, for instance. This accelerates the development process. To make your styles locally scoped, prefix your CSS files with the name .module.css.

Let's generate two components with the same class names to see how local styles work. Create a new components folder and within it, devise two folders: user and quote, like this:

css modules folder

Use our previous example's code and insert it inside the Quote.jsx file:

import React from 'react';
import styles from './Quote.module.css';

function Quote() {
   return (
      <div className={styles.wrapper}>
         <h2>It's never too late to be whoever you want to be</h2>
         <img className={styles.pic} src="https://shorturl.at/EORT4" />
      </div>
   );
}

export default Quote;

See that we imported the styles and accessed them using styles.wrapper and styles.pic syntax. This instructs React to navigate to the Quote.module.css file and search for the wrapper and pic classes. If they are present, React will apply their styles to the HTML elements.

Here are the styles for the Quote component:

.wrapper {
    text-align: center;
    color: #92d1c2
}

.pic {
    width: 300px;
    border-radius: 10px
}

It's time to flesh out the User component. Its structure will be like the Quote component: it will have a wrapper div, an h2 tag, and an img tag. Here is how it looks:

import React from 'react';
import styles from './User.module.css';

function User() {
   return (
      <div className={styles.wrapper}>
         <h2>I'm a User component and I have my own styles</h2>
         <img className={styles.pic} src="https://shorturl.at/mwxy9" />
      </div>
   );
}

export default User;

And here are the User's styles:

.wrapper {
    text-align: center;
    color: #cb92d1
}

.pic {
    width: 500px;
    border-radius: 50%
}

Note that both components have two classes with the same names, wrapper and pic. But, properties within those classes differ for each component: the photos have different width and border radius, and the wrapper color also differs. Let's render both components to see the results. Import them into the App.jsx file and render in the return block:

import React from 'react';
import Quote from '../quote/Quote'
import User from '../user/User';

function App() {
   return (
      <div>
         <Quote />
         <User />
      </div>
   );
}

export default App;

Here's how it looks:

css module example

Great! Even though the components have class names that are the same, the actual styles didn't get mixed or override each other. If you're curious about how this is possible, inspect the elements in the dev tools. You will see that the class names are joined with some random strings like this:

<div class="_wrapper_1nis1_1">
  <h2>It's never too late to be whoever you want to be</h2>
  <img class="_pic_1nis1_11" src="https://shorturl.at/EORT4">
</div>

These get added automatically to guarantee that each class name is distinct, ensuring that styles do not merge into other parts of the application.

Dynamic styles

React's dynamic styles let you alter a component's styles based on its state or props. You typically do this with JavaScript expressions in your JSX code. The symbols && and : are for conditional logic in JavaScript, and you can use them to apply these dynamic styles in React.

Commonly, dynamic styles work in connection with props and state variables defined with the useState hook. However, we'll keep things simple and use basic examples. Imagine you have an email input field. If the user enters an email in a correct format, you want this field to be green. If they make a mistake, you want it to turn red as a visual cue. Here's how you might accomplish this:

import React from 'react';

function App() {
   const isValid = true;

   return (
      <div>
         <label for="email" style={{ color: isValid ? 'green' : 'red', margin: '1em' }}>
            Email
         </label>
         <input id="email" type="email" style={{ border: '1.5px solid grey', borderColor: isValid ? 'green' : 'red', }} />
      </div>
   );
}

export default App;

In this code chunk, we introduce a constant labeled isValid. When its value equals true, we color the label and input border green; if it's false, we turn them red. The logic isValid ? 'green' : 'red' works much like an if/else construction.

Right now, isValid is set to true, so everything appears green:

valid input

Try changing the variable to false and observe how it alters the view.

The && operator also enables conditional rendering of styles. Here's a demonstration:

import React from 'react';
import './App.css'

function App() {
  const isBig = true;

   return (
      <div style={{fontSize: isBig && '1.5rem'}}>
        What a beautiful day!
      </div>
   );
}

export default App;

In this case, the font size becomes "1.5rem" only when isBig equals true. If isBig is false, the font size remains unchanged. In JavaScript, && serves as a "short-circuit" operator, meaning that if the first operand is false, the second operand doesn't come into play. You can check the element's font size using your development tools. It should differ based on the isBig value.

These examples offer just a glimpse of how you can wield dynamic styles in React. The key is to leverage JavaScript's expressive power within your JSX code to create styles that can adapt based on your component's state or props.

Conclusion

React delivers a variety of ways to style components. Inline styles are straightforward and effortless to utilize but miss some CSS features. Importing styles helps you segregate the styles from your JavaScript code. CSS Modules offer local scope to stop styles from influencing other application sections. Dynamic styles let you modify the styles of a component depending on its state or props. You'll decide on the method based on what your project requires and what you prefer personally.

5 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo