When working with styled components, how can I effectively apply different styles using two layers of class names within the component declaration?

In my next.js project, I have developed a Container component with specific styles. As I incorporate this container component throughout the site, I aim to assign it a className for context-based styling.

Illustrated below is an example of the Container component:

    const Container = (props) => (
    <>
        <div className="container">
            {props.children}
        </div>

        <style jsx>{`
            .container{
                width: 100%;
                max-width: 1200px;
                margin: 0 auto;
            }
        `}</style>
    </>
)

export default Container;

The Container has been successfully styled to have a maximum width of 1200px and centered using auto margins. All functioning as intended.

I am now considering utilizing this component in the header section of my website. In the case of the header, I wish for the Container component to behave as a flexbox:

import Container from './Container'

const Header = (props) => (
    <>
        <header>
            <Container className="header-col">
                <div>
                    <h1>{props.title}</h1>
                </div>
                <nav>
                    <ul>
                        {/* Navigation items */}
                    </ul>
                </nav>
            </Container>
        </header>

        <style jsx>{`
            .header-col{
                display: flex;
                justify-content: space-between;
            }
        `}</style>
    </>
)

export default Header;

Upon reviewing the site, I observed that the flexbox style set for the Container component within the header is not being applied.

I anticipated the className to trigger additional styles, but it seems to treat it as a prop rather than a class name. However, I prefer maintaining code reusability by implementing style inheritance on components.

Is there a way to achieve this?

Appreciate any guidance provided!

Answer №1

Utilizing styled components is the way to go for this task:

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

export default function App() {
  return (
    <>
      <Container custom={"header"}>
        <h1>Very fancy h1 with flex display</h1>
      </Container>
      <Container custom={"regular"}>
        <h1>Non-fancy h1 with no flex display</h1>
      </Container>
    </>
  );
}

const Container = styled.div`
  display: ${(props) => (props.custom === "header" ? "flex" : "block")};
  
  & h1 {
    font-family: ${(props) =>
      props.custom === "header"
        ? '"Courier New", Courier, monospace'
        : '"Arial Black", Gadget, sans-serif'};
  }
`;

The customized styled component I've created above takes the custom prop and adjusts values conditionally. Additionally, I added styling to the font to clearly differentiate between the two <Container> elements.


To address scalability concerns, like accommodating different themes, consider using ThemeProvider:

import React from "react";
import styled, { ThemeProvider } from "styled-components";

export default function App() {
  return (
    <>
      <ThemeProvider theme={ContainerHeader}>
        <Container>
          <h1>Very fancy h1 with flex display</h1>
        </Container>
      </ThemeProvider>
      <Container theme={"regular"}>
        <h1>Non-fancy h1 with no flex display</h1>
      </Container>
    </>
  );
}

const Container = styled.div`
  display: ${(props) => props.theme.display};
  & h1 {
    font-family: ${(props) => props.theme.h1Font};
  }
`;

Container.defaultProps = {
  theme: {
    display: "block",
    h1Font: '"Arial Black", Gadget, sans-serif'
  }
};

const ContainerHeader = {
  display: "flex",
  h1Font: '"Courier New", Courier, monospace'
};

Explore the solution further on CodeSandbox: https://codesandbox.io/s/stack-conditional-styled-components-vmnpn?file=/src/App.js:0-773

Answer №2

After some exploration, I think I've stumbled upon the solution to my query (I'll keep this question open for a few more days just in case there are further enhancements).

To apply styles efficiently, you can utilize the "global" flag with styled JSX and incorporate extra class names in the component using props.className.

Here's an example of a Parent Container component utilizing props.className:

const Container = (props) => (
    <>
        <div className={`container ${props.className}`}>
            {props.children}
        </div>

        <style jsx>{`
            .container{
                width: 100%;
                max-width: 1200px;
                margin: 0 auto;
            }
        `}</style>
    </>
)

export default Container;

Subsequently, when implementing this component, you can extend the styles even further with the global flag within <style jsx>:

Example of the Container being utilized and styled elaborately within the header:

import Container from './Container';

const Header = (props) => (
    <>
        <header>
            <Container className="header-col">

                <div>
                    <h1>{props.title}</h1>
                </div>


                <nav>
                    <ul>
                        <li>Hello</li>
                        <li>There</li>
                    </ul>
                </nav>
            </Container>
        </header>

        <style jsx global>{`
            .header-col{
                display: flex;
                justify-content: space-between;
            }
        `}</style>
    </>
)

export default Header;

While not flawless, the method is quite effective in my view:

  • The global flag extends your styles globally, allowing other components to access these styles (from what I've observed)
  • Ensure that your components accept props.className to add further class names for this global style

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Leveraging environment variables in a 'use client' module within a Next.js application

I am facing the issue of not being able to access my .env variables such as GraphQL URL and access token in a 'use client' Apollo context wrapper component that is rendered client-side. Is there any solution for this in Next.js v13? Here is the ...

Stay tuned for Quasar's input validation event notifications

Within my Vue3 Quasar application, I have implemented a component structure similar to the following: <template> <div class="q-pa-md"> <div id="myCustomLabel">{{ props.label }}</div> <q-input r ...

What is the best way to handle HTML files that have the same name as folders?

I am looking to incorporate a News section on my website with the unique URL: mysite.com/news Each news article should be stored in a specific folder named "News" like this: mysite.com/news/2021 However, when I attempt to access the news.html file (witho ...

Sending react table information to react modal

As a beginner with React, I'm facing challenges in passing data from react-table to an "edit" modal and haven't found a suitable solution yet. The data is fetched from the database using Axios API call and displayed in a react-table. My objective ...

Customize MUI Tabs to resemble the design of Bootstrap Nav Tabs

Looking to customize Material UI Tabs to resemble Bootstrap Tabs. Made significant changes, but struggling with removing the border-bottom on the activeTab. In Bootstrap, they use marginBottom: -1px on the active tab, but it doesn't work for me. Any s ...

Change the order of the table data elements using the nth-child CSS selector

I need the second td in my table to appear on top of the first one when I resize the screen. @media screen and (min-width: 200px) and (max-width: 872px) { td :nth-child(1) {display:bottom} td :nth-child(2) {display:top} } <table border="0" cell ...

Utilizing CSS to Properly Position HTML Elements

Check out my code on jsFiddle I'm facing some challenges in positioning HTML elements using CSS. While I grasp the fundamental concepts of block and inline elements, implementing them in real coding scenarios can be confusing. I've shared my HTM ...

Do we really need to create our own action creators in Redux Toolkit?

As I delve into implementing the redux toolkit in my react projects, I've come up with a structure for writing slices using redux-thunk to handle API requests. import { createSlice } from "@reduxjs/toolkit"; import axios from "axios&quo ...

Custom-designed foundation UI element with a parameter triggers TypeScript issue

When running this tsx code: import React from "react"; import BaseButton from "@mui/base/Button"; import styled from "@emotion/styled"; export const enum BUTTON_TYPE { MAIN = "main", LINK = "link", } ...

Execute a nested package.json script

I have a folder named package-scripts where I keep all the scripts for building in the react environment: const npsUtils = require('nps-utils') module.exports = { scripts: { default: 'react-scripts start', build: 'react- ...

What steps can be taken to address the issue of missing headers error and ensure proper validation of

While developing a React and Laravel website, I encountered an issue in the console. The error seems to be related to my cors.php file, which is responsible for handling cross-origin resource sharing. The cors.php file contains configurations for allowed ...

What is the best way to incorporate a CSS transition without any dynamic property changes?

Is there a way to add a transition effect to a header when its size changes without a specified height value in the CSS? The header consists of only text with top and bottom padding, so as the text changes, the height adjusts accordingly. How can I impleme ...

What are some React component libraries compatible with Next.js 13.1?

I'm exploring Next.js and experimenting with version 13.1 and the new app directory. Is it feasible to accomplish this without sacrificing the advantages of server controls? An error message I encountered states: You're attempting to import a c ...

The conditional statement to check for an empty object does not trigger any actions

My goal is to display a success message once users successfully register without any errors. I have an errors reducer object in Redux that stores errors sent from the backend. The logic is set up so that if the errors object is empty, it shows the success ...

A step-by-step guide on clearing a TextInput programmatically with the help of

Is there a way to automatically clear the TextInput after submitting the form using useRef? const inputRef = useRef() I have tried the following code to clear the input field, but it is not working: const clearInput = () => { inputRef.cur ...

Looking to design an interactive grid for generating dynamic thumbnails

I am a beginner in the field of web development and I have a desire to create a website for showcasing my portfolio. This website should feature project thumbnails along with brief descriptions, all of which should be displayed dynamically. Although I poss ...

Guide to stacking blocks on top of each other

How can I create even spacing between blocks of different heights? For instance, in the image below, you can see that block 2 should be positioned directly under block 1. https://i.stack.imgur.com/RnYbP.png https://i.stack.imgur.com/LHvlz.png ...

ReactJs route path with specific id parameter results in displaying the wrong components

I attempted to utilize Route for redirecting to a component, but it is showing both components simultaneously. Specifically for /test/new, I want to display only the NewRequest component. The issue seems to be related to the /:id/ parameter, but I am uns ...

Do I still need to include getStaticPaths if I am already utilizing Link within the HTML in getStaticProps?

If I utilize getStaticProps to render a page as a table of contents, will NextJS automatically generate those pages statically by following the links and calling getStaticProps for each one? In this scenario, the file /page/[id].js represents a dynamic pa ...

Troubleshooting why SCSS styling is not properly applying to the active class in Next.js

Currently, I am in the process of learning Next.js and implementing SCSS for styling. While reviewing my work, I noticed that the styles are functioning well as shown in image 2 but encounter issues when using the `.active` class. https://i.stack.imgur.c ...