React - The Complete Guide

Section 06: Styling Components - Make Your Apps Look Good

olivia_yj 2022. 11. 11. 21:38

The goals

💪🏻Conditional & Dynamic Styles

✌🏻Styled Components

👍🏻CSS Modules

 

 

Inline Styles

React components are composed of JSX elements. But just because you’re not writing regular HTML elements doesn’t mean you can’t use the old inline style method.

The only difference with JSX is that inline styles must be written as an object instead of a string.

Here is a simple example:

import React from "react";

export default function App() {
  return (
      <h1 style={{ color: "red" }}>Hello World</h1>
  );
}

In the style attribute above, the first set of curly brackets will tell your JSX parser that the content between the brackets is JavaScript (and not a string). The second set of curly bracket will initialize a JavaScript object.

Style property names that have more than one word are written in camelCase instead of using the traditional hyphenated style. For example, the usual text-align property must be written as textAlign in JSX:

import React from "react";

export default function App() {
  return (
      <h1 style={{ textAlign: "center" }}>Hello World</h1>
  );
}

Because the style attribute is an object, you can also separate the style by writing it as a constant. This way, you can reuse it on other elements as needed:

import React from "react";

const pStyle = {
  fontSize: '16px',
  color: 'blue'
}

export default function App() {
  return (
      <p style={pStyle}>The weather is sunny with a small chance of rain today.</p>
  );
}

If you need to extend your paragraph style further down the line, you can use the object spread operator. This will let you add inline styles to your already-declared style object:

import React from "react";
const pStyle = {
  fontSize: "16px",
  color: "blue"
};
export default function App() {
  return (
    <>
      <p style={pStyle}>
        The weather is sunny with a small chance of rain today.
      </p>
      <p style={{ ...pStyle, color: "green", textAlign: "right" }}>
        When you go to work, don't forget to bring your umbrella with you!
      </p>
    </>
  );
}

Inline styles are the most basic example of a CSS in JS styling technique.

One of the benefits in using the inline style approach is that you will have a simple component-focused styling technique. By using an object for styling, you can extend your style by spreading the object. Then you can add more style properties to it if you want.

But in a big and complex project where you have a hundreds of React components to manage, this might not be the best choice for you.

You can’t specify pseudo-classes using inline styles. That means :hover, :focus, :active, or :visited go out the window rather than the component.

Also, you can’t specify media queries for responsive styling. Let’s consider another way to style your React app.

Dynamic CSS class 

 

Styled Components

Styled Components is a library designed for React and React Native. It combines both the CSS in JS and the CSS Modules methods for styling your components.

Let me show you an example:

import React from "react";
import styled from "styled-components";

// Create a Title component that'll render an <h1> tag with some styles
const Title = styled.h1`
  font-size: 1.5em;
  text-align: center;
  color: palevioletred;
`;

export default function App() {
  return <Title>Hello World!</Title>;
}

When you write your style, you’re actually creating a React component with your style attached to it. The funny looking syntax of styled.h1 followed by backtick is made possible by utilizing JavaScript’s tagged template literals.

Styled Components were created to tackle the following problems:

  • Automatic critical CSS: Styled-components keep track of which components are rendered on a page, and injects their styles and nothing else automatically. Combined with code splitting, this means your users load the least amount of code necessary.
  • No class name bugs: Styled-components generate unique class names for your styles. You never have to worry about duplication, overlap, or misspellings.
  • Easier deletion of CSS: It can be hard to know whether a class name is already used somewhere in your codebase. Styled-components makes it obvious, as every bit of styling is tied to a specific component. If the component is unused (which tooling can detect) and gets deleted, all of its styles get deleted with it.
  • Simple dynamic styling: Adapting the styling of a component based on its props or a global theme is simple and intuitive, without you having to manually manage dozens of classes.
  • Painless maintenance: You never have to hunt across different files to find the styling affecting your component, so maintenance is a piece of cake no matter how big your codebase is.
  • Automatic vendor prefixing: Write your CSS to the current standard and let styled-components handle the rest.

You get all of these benefits while still writing the same CSS you know and love – just bound to individual components.

If you’d like to learn more about styled components, you can visit the documentation and see more examples.

Styled Components dynamic props

We are going to create a styled component, so a basic HTML-button, as defined by the “button”, which we can enhance inside the backticks with some kind of CSS. The typical CSS syntax is noticeable, but as a value for the background color we can now pass a prop.

const Button = styled.button`
   background-color: ${props => props.color};
`

Then we can simply use this component as usual in React.js by the variable name. As Prop for this component we now pass a color valid for CSS.

function App() {
  return (
    <div className=”App”>
      <Button color=”green”>This is a green button</Button>
      <Button color=”blue”>This is a blue button</Button>
    </div>
  )
}

As a result you should now see two buttons. A green and a blue one, because we have given both colors as prop for “color” of the buttons.

Pretty cool so far, huh? But we can even work with Booleans!

As already known, in CSS we can make elements visible or invisible with the visibility property, depending on whether we specify “visible” or “hidden”.

To use this we create a new component. The JS code in it is the shorthand syntax for if-else that we want to use to make the component visible or not, depending on the prop we pass.
Our syntax means that if the props “visible” is true, we want to set the CSS value visible for the visibility property, and if it is false, we want to set the CSS value to hidden. So true means visible, false means invisible.

const ToggleButton = styled.button`
  /* if true, button will be visible */
  visibility: ${props => (props.visible ? “visible” : “hidden”)};'
`

Now there are two ways to control the visibility property via the component.
If we do not pass the prop at all, React.js will set the value for it to false by default. If we pass it, even without a value behind it, since we don’t need it for booleans, React.js will pass true. The example is as always below.

<ToggleButton visible>This button is visible</ToggleButton> <ToggleButton>This button is not visible</ToggleButton>

But if we want to connect the whole thing with e.g. our state, we can also use JavaScript syntax. The result is the same, but you can use a variable for true and false, which is one of both.

<ToggleButton visible={true}>This button is visible</ToggleButton> <ToggleButton visible={false}>
  This button is not visible
</ToggleButton>

We used this props styling like this,

import React, { useState } from 'react';
import styled from 'styled-components';

import Button from '../../UI/Button/Button';
import './CourseInput.css';

const FormControl = styled.div`
  margin: 0.5rem 0;

  & label {
    font-weight: bold;
    display: block;
    margin-bottom: 0.5rem;
    color: ${props => (props.invalid ? 'red' : 'black')};
  }

  & input {
    display: block;
    width: 100%;
    border: 1px solid ${props => (props.invalid ? 'red' : '#ccc')};
    background: ${props => (props.invalid ? '#ffd7d7' : 'transparent')};
    font: inherit;
    line-height: 1.5rem;
    padding: 0 0.25rem;
  }

  & input:focus {
    outline: none;
    background: #fad0ec;
    border-color: #8b005d;
  }
`;

Media Query

 

CSS Modules

A CSS module is a regular CSS file with all of its class and animation names scoped locally by default.

Each React component will have its own CSS file, and you need to import the required CSS files into your component.

In order to let React know you’re using CSS modules, name your CSS file using the [name].module.css convention.

Here is an example:

.BlueParagraph {
  color: blue;
  text-align: left;
}
.GreenParagraph {
  color: green;
  text-align: right;
}
import React from "react";
import styles from "./App.module.css";
export default function App() {
  return (
    <>
      <p className={styles.BlueParagraph}>
        The weather is sunny with a small chance of rain today.
      </p>
      <p className={styles.GreenParagraph}>
        When you go to work, don't forget to bring your umbrella with you!
      </p>
    </>
  );
} 

When you build your app, webpack will automatically look for CSS files that have the .module.css name. Webpack will take those class names and map them to a new, generated localized name.

Here is the sandbox for the above example. If you inspect the blue paragraph, you’ll see that the element class is transformed into _src_App_module__BlueParagraph.

CSS Modules ensures that your CSS syntax is scoped locally.

Another advantage of using CSS Modules is that you can compose a new class by inheriting from other classes that you’ve written. This way, you’ll be able to reuse CSS code that you’ve written previously, like this:

.MediumParagraph {
  font-size: 20px;
}
.BlueParagraph {
  composes: MediumParagraph;
  color: blue;
  text-align: left;
}
.GreenParagraph {
  composes: MediumParagraph;
  color: green;
  text-align: right;
}

Finally, in order to write normal style with a global scope, you can use the :global selector in front of your class name:

:global .HeaderParagraph {
  font-size: 30px;
  text-transform: uppercase;
}

You can then reference the global scoped style like a normal class in your JS file:

<p className="HeaderParagraph">Weather Forecast</p>

 

Sources

https://beta.reactjs.org/apis/react/useState

 

useState

A JavaScript library for building user interfaces

beta.reactjs.org

https://styled-components.com/

 

styled-components

Visual primitives for the component age. Use the best bits of ES6 and CSS to style your apps without stress 💅🏾

styled-components.com