YouTube Courses - Learn Smarter

YouTube-Courses.site transforms YouTube videos and playlists into structured courses, making learning more efficient and organized.

Styled Components in React: An In-Depth Guide



This chapter will explore Styled Components, a popular library for styling React applications. Styled Components allows developers to write CSS directly within their JavaScript code in an elegant and reusable manner. While various approaches exist for styling React components, Styled Components offers a unique method focused on component encapsulation and maintainability.

Introduction to Styled Components

Styled Components provides a way to write CSS in JavaScript (often referred to as CSS-in-JS). This approach offers several benefits, including component-level styling and improved code organization.

CSS-in-JS: A technique of writing CSS styles within JavaScript files, often associated with component-based frameworks like React. It allows for component-scoped styling and dynamic styling capabilities.

While some developers may prefer traditional CSS stylesheets, Styled Components presents a compelling alternative, particularly for projects emphasizing component-based architecture.

Why Consider Styled Components?

There isn’t a single “correct” way to style React applications. The choice often comes down to personal or team preference and project requirements. While global stylesheets are perfectly valid, Styled Components excels in scenarios where:

  • Component Encapsulation is Key: Styled Components promotes a style encapsulation approach, where styles are directly associated with the components they style. This reduces the risk of style conflicts and enhances component reusability.
  • Maintainability and Organization are Prioritized: By co-locating styles with components, Styled Components improves code organization and makes it easier to maintain styles as the application grows.
  • Dynamic Styling is Frequently Used: Styled Components simplifies dynamic styling based on component props or application state.

Styled Components is widely adopted within the React ecosystem. Understanding it is beneficial, as you are likely to encounter it in various projects.

Course Structure

This chapter is structured in two parts:

  • Fundamentals (First Section): We will begin by covering the fundamental concepts of Styled Components, including:

    • Creating Styled Components
    • Nesting Styles
    • Using Props for Dynamic Styling
    • Implementing Themes for Consistent Styling
    • Applying Global Styles
  • Project-Based Learning (Subsequent Sections): After establishing a solid understanding of the fundamentals, we will apply our knowledge by building a practical project: a landing page inspired by the “Huddle landing page” challenge from Front-End Mentor. This project will allow us to utilize the concepts learned, including props, media queries, and more.

Let’s begin by setting up our development environment and exploring the basics of Styled Components.

Setting Up and Fundamentals

To start, we assume you have a basic React application set up, ideally using Create React App. If you don’t, you can quickly create one using the following command in your terminal:

npx create-react-app styled-components-demo
cd styled-components-demo
npm start

This will create a new React application and start the development server.

Installation

First, we need to install the styled-components library. Open a new terminal window, navigate to your project directory, and run the following command using npm or yarn:

npm install styled-components

or

yarn add styled-components

This command will add Styled Components as a dependency to your project.

Cleaning Up the Default React App

After installation, let’s clean up the default React app to start with a clean slate.

  1. Delete Unnecessary Files: Navigate to the src folder and delete:

    • logo.svg (if present)
    • App.css
    • index.css
  2. Update index.js: Open index.js and remove the line that imports index.css:

    // Remove this line:
    // import './index.css';
  3. Update App.js: Open App.js and:

    • Remove the import statements for logo.svg, App.css, and index.css.
    • Clear the content within the main div in the return statement and replace it with a simple <h1>Hello World</h1>.
    import React from 'react';
    // Remove these lines:
    // import logo from './logo.svg';
    // import './App.css';
    
    function App() {
      return (
        <div>
          <h1>Hello World</h1>
        </div>
      );
    }
    
    export default App;

With these steps, you have a basic, unstyled React application ready for integrating Styled Components.

Creating Your First Styled Component

In traditional React styling, you might add classes (using className in JSX) to HTML elements and then define those classes in separate CSS files. However, Styled Components allows us to create styled components directly in our JavaScript files.

Let’s create a Container component that centers content on the page and sets a specific width.

  1. Create a styles folder: Inside the src folder, create a new folder named styles.

  2. Create Container.styled.js: Inside the styles folder, create a new file named Container.styled.js. The .styled.js naming convention is a common practice to distinguish Styled Component files.

  3. Define the Styled Container: Open Container.styled.js and add the following code:

    import styled from 'styled-components';
    
    export const Container = styled.div`
      max-width: 1000px;
      padding-left: 20px;
      padding-right: 20px;
      margin: 0 auto;
    `;

    Let’s break down this code:

    • import styled from 'styled-components';: This line imports the styled object from the styled-components library. This object is the primary tool for creating styled components.
    • export const Container = styled.div``...``;: This line creates and exports a styled component named Container.
      • styled.div: This indicates that we are creating a styled div element. You can use other HTML tags like styled.span, styled.header, styled.button, etc., to style different HTML elements.
      • `...`: These are backticks, which are used to define a tagged template literal in JavaScript. Within these backticks, you write standard CSS syntax.
  4. Import and Use Container in App.js: Open App.js and modify it as follows:

    import React from 'react';
    import { Container } from './styles/Container.styled'; // Import the Container component
    
    function App() {
      return (
        <Container> {/* Use the Container component */}
          <h1>Hello World</h1>
        </Container>
      );
    }
    
    export default App;
    • import { Container } from './styles/Container.styled';: This line imports the Container styled component we just created. Note the curly braces {} because it’s not a default export.
    • <Container> and </Container>: We wrap our <h1>Hello World</h1> element with the Container component. This applies the styles defined in Container.styled.js to the content within it.

Now, if you run your React application, you should see “Hello World” centered on the page with padding on the left and right, due to the styles applied by the Container component.

Understanding Tagged Template Literals

Styled Components utilizes JavaScript’s tagged template literals.

Tagged Template Literal: A more advanced form of template literals in JavaScript that allows functions to have control over how template literals are interpreted. In Styled Components, the styled.div (or other HTML tag) acts as the “tag” function, processing the CSS within the backticks.

The CSS written inside the backticks is not just a regular string. Styled Components parses this CSS, and when the Container component (in our example) is rendered, it dynamically generates unique class names and injects the corresponding CSS into the document’s <head> section. This ensures that the styles are scoped to the Container component and don’t interfere with other parts of the application.

Creating a Header Component with Styled Components

Let’s create a more complex component, a Header, and apply styles using Styled Components.

  1. Create Header.js: Inside the src/components folder (create this folder if it doesn’t exist), create a new file named Header.js. This will be our regular React component.

  2. Create Header.styled.js: Inside the src/styles folder, create a new file named Header.styled.js. This will contain the Styled Components for our Header.

  3. Define Styled Components in Header.styled.js: Open Header.styled.js and add the following code:

    import styled from 'styled-components';
    
    export const StyledHeader = styled.header`
      background-color: #ebfbff;
      padding: 40px 0;
    `;
    
    export const StyledNav = styled.nav`
      display: flex;
      align-items: center;
      justify-content: space-between;
      margin-bottom: 40px;
    
      @media (max-width: ${({ theme }) => theme.mobile}) {
        flex-direction: column;
        align-items: center;
      }
    `;
    
    export const StyledLogo = styled.img`
      @media (max-width: ${({ theme }) => theme.mobile}) {
        margin-bottom: 40px;
      }
    `;

    Here, we’ve created three styled components:

    • StyledHeader: Styles the <header> HTML5 tag with a background color and padding.

    • StyledNav: Styles the <nav> tag to create a navigation bar using flexbox, with responsiveness for smaller screens using a media query.

    • StyledLogo: Styles <img> tag for logo, adding margin-bottom in mobile view using media query.

    Media Query: A CSS technique that allows applying different styles based on the characteristics of the device or browser, most commonly the viewport width. In Styled Components, media queries are written directly within the CSS template literal, often leveraging template literals for dynamic values.

    • @media (max-width: ${({ theme }) => theme.mobile}): This is a media query targeting screens with a maximum width defined by theme.mobile (we will define themes later).
  4. Create Header React Component in Header.js: Open Header.js and add the following code:

    import React from 'react';
    import { StyledHeader, StyledNav, StyledLogo } from '../styles/Header.styled'; // Import styled components
    import { Container } from '../styles/Container.styled'; // Import Container component
    
    function Header() {
      return (
        <StyledHeader>
          <Container>
            <StyledNav>
              <StyledLogo src="./images/logo.svg" alt="" />
              <button>Try It Free</button>
            </StyledNav>
    
            {/* ... rest of header content will be added later ... */}
    
          </Container>
        </StyledHeader>
      );
    }
    
    export default Header;
    • We import the styled components StyledHeader, StyledNav, and StyledLogo from Header.styled.js, and the Container component.
    • We use these styled components instead of regular HTML tags in our JSX structure.
  5. Update App.js to include Header: Open App.js and update it to include the Header component:

    import React, { Fragment } from 'react'; // Import Fragment
    import Header from './components/Header'; // Import Header component
    import { Container } from './styles/Container.styled';
    
    function App() {
      return (
        <Fragment> {/* Use Fragment to wrap multiple components */}
          <Header />
          <Container>
            <h1>Hello World</h1>
          </Container>
        </Fragment>
      );
    }
    
    export default App;
    • We import Fragment from React to wrap multiple components in the return statement without adding an extra DOM element.
    • We import and render the Header component above the Container.

Now, your application should display a styled header with a navigation bar containing a logo (you’ll need to place logo.svg in the public/images folder - you can get it from the mentioned GitHub repository or use any SVG logo for testing) and a “Try It Free” button.

Nesting Styles

Styled Components allows you to nest CSS selectors, similar to CSS pre-processors like Sass or Less. This improves the organization and readability of your styles, especially for complex components.

In Header.styled.js, within the StyledHeader definition, we can add styles for the h1 element that might be present inside the header:

export const StyledHeader = styled.header`
  background-color: #ebfbff;
  padding: 40px 0;

  h1 { /* Nested style for h1 within StyledHeader */
    color: red;
  }

  &:hover { /* Nesting for pseudo-selector :hover for StyledHeader itself */
    background-color: black; /* Example, not to be kept for header */
    color: white; /* Example, not to be kept for header */
  }
`;
  • h1 { ... }: Styles any h1 element that is a direct or indirect child of the StyledHeader component.
  • &:hover { ... }: Uses the ampersand & to refer to the StyledHeader component itself, allowing you to style pseudo-selectors like :hover, :active, :focus, etc.

CSS Pre-processor: A tool that extends the capabilities of standard CSS by adding features like variables, nesting, mixins, and functions. Sass and Less are popular examples. Styled Components’ nesting feature provides a similar organizational benefit within JavaScript.

Note: While nesting is available, it’s important to use it judiciously to maintain clarity and avoid overly complex selectors. Over-nesting can sometimes make styles harder to understand and maintain.

Using Props for Dynamic Styling

One of the powerful features of Styled Components is the ability to dynamically style components based on props passed to them.

Let’s modify the StyledHeader to accept a bg prop to change its background color dynamically.

  1. Modify StyledHeader in Header.styled.js:

    export const StyledHeader = styled.header`
      background-color: ${(props) => props.bg || '#ebfbff'}; /* Dynamic background color from props */
      padding: 40px 0;
    `;
    • background-color: ${(props) => props.bg || '#ebfbff'};: This line sets the background-color style dynamically.
      • ${(props) => props.bg || '#ebfbff'}: This is a JavaScript arrow function within the CSS template literal. It receives the props object as an argument.
      • props.bg: Accesses the bg prop passed to the StyledHeader component.
      • || '#ebfbff': If the bg prop is not provided (or is falsy), it defaults to #ebfbff (the original light blue color).
  2. Pass the bg prop in App.js (or Header.js):

    In App.js (or within the Header component if you want to set it there), you can now pass the bg prop to the Header component:

    // In App.js
    <Header bg="red" />; // Example: set background to red
    <Header />;        // Example: use default background color

    Or within Header.js:

    // In Header.js
    <StyledHeader bg="lightgreen"> {/* Example: set background to light green */}
        {/* ... header content ... */}
    </StyledHeader>
    
    <StyledHeader> {/* Example: use default background color */}
        {/* ... header content ... */}
    </StyledHeader>

Now, if you pass the bg prop, the header’s background color will change accordingly. If you don’t pass the bg prop, it will use the default light blue color.

Themes for Consistent Styling

Themes in Styled Components provide a centralized way to manage and share styling values across your application, such as colors, fonts, breakpoints, and spacing units. This promotes consistency and makes it easier to update your application’s visual style.

  1. Create a Theme Object in App.js:

    In App.js, before the App component function, define a theme object:

    const theme = {
      colors: {
        header: '#ebfbff',
        body: '#fff',
        footer: '#003333',
      },
      mobile: '768px', // Example mobile breakpoint
    };

    This theme object contains:

    • colors: An object holding color values for different parts of the application (header, body, footer).
    • mobile: A breakpoint value for mobile devices.
  2. Use ThemeProvider to Provide the Theme:

    Import ThemeProvider from styled-components in App.js and wrap your application’s components with it. Pass the theme object as a prop to ThemeProvider:

    import React, { Fragment } from 'react';
    import Header from './components/Header';
    import { Container } from './styles/Container.styled';
    import { ThemeProvider } from 'styled-components'; // Import ThemeProvider
    
    const theme = { /* ... theme object defined earlier ... */ };
    
    function App() {
      return (
        <ThemeProvider theme={theme}> {/* Wrap components with ThemeProvider */}
          <Fragment>
            <Header />
            <Container>
              <h1>Hello World</h1>
            </Container>
          </Fragment>
        </ThemeProvider>
      );
    }
    
    export default App;
  3. Access Theme Values in Styled Components:

    Now, you can access theme values within your styled components using the theme prop. For example, in Header.styled.js, modify StyledHeader to use the header color from the theme:

    export const StyledHeader = styled.header`
      background-color: ${({ theme }) => theme.colors.header}; /* Access header color from theme */
      padding: 40px 0;
    `;
    • background-color: ${({ theme }) => theme.colors.header};: We use destructuring in the arrow function’s parameter list to directly access the theme prop. Then, we access theme.colors.header to get the header color defined in our theme object.

Now, the StyledHeader’s background color is driven by the theme.colors.header value. If you change the color in the theme object, it will automatically update across all components using that theme value.

Global Styles for Baseline and Reset

Styled Components also allows you to define global styles, which are applied to the entire application. This is useful for setting baseline styles, resets, and common styles for HTML elements like body, p, a, etc.

  1. Create GlobalStyles.js in styles folder:

    Inside the src/styles folder, create a new file named GlobalStyles.js.

  2. Define Global Styles:

    Open GlobalStyles.js and add the following code:

    import { createGlobalStyle } from 'styled-components';
    
    const GlobalStyles = createGlobalStyle`
      *,
      *::before,
      *::after {
        box-sizing: border-box; /* Apply border-box to all elements */
      }
    
      body {
        background: ${({ theme }) => theme.colors.body}; /* Body background from theme */
        color: hsl(192, 100%, 9%);
        font-family: 'Poppins', sans-serif;
        font-size: 1.15em;
        margin: 0;
      }
    
      p {
        opacity: 0.6;
        line-height: 1.5;
      }
    
      img {
        max-width: 100%;
      }
    `;
    
    export default GlobalStyles;
    • import { createGlobalStyle } from 'styled-components';: Imports createGlobalStyle function.
    • const GlobalStyles = createGlobalStyle``...``;: Creates a global style component using createGlobalStyle.
    • Within the backticks, you write CSS that will be applied globally.
      • Reset styles like box-sizing: border-box;

      • body styles including background color from the theme (theme.colors.body).

      • Styles for p and img elements.

    Global Styles: CSS styles that are intended to affect the entire webpage or application, typically including resets, baseline styles for common HTML elements, and application-wide styling rules.

  3. Import and Include GlobalStyles in App.js:

    Import GlobalStyles in App.js and render it as a component, typically at the top level, inside the ThemeProvider:

    import React, { Fragment } from 'react';
    import Header from './components/Header';
    import { Container } from './styles/Container.styled';
    import { ThemeProvider } from 'styled-components';
    import GlobalStyles from './styles/GlobalStyles'; // Import GlobalStyles
    
    const theme = { /* ... theme object ... */ };
    
    function App() {
      return (
        <ThemeProvider theme={theme}>
          <GlobalStyles /> {/* Include GlobalStyles component */}
          <Fragment>
            <Header />
            <Container>
              <h1>Hello World</h1>
            </Container>
          </Fragment>
        </ThemeProvider>
      );
    }
    
    export default App;

Now, the global styles defined in GlobalStyles.js will be applied to your entire application. This includes the body background color being taken from the theme, font styles, and the box-sizing reset.

Conclusion of Fundamentals

This section covered the fundamental concepts of Styled Components. You have learned how to:

  • Create basic styled components using styled.tagname``...``;
  • Nest styles within styled components
  • Use props to dynamically style components
  • Implement themes for consistent styling across your application
  • Apply global styles for resets and baseline styling

With these fundamentals in place, you are now ready to move on to building a practical project to further solidify your understanding and explore more advanced techniques with Styled Components. The next sections will guide you through building a landing page project.