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

The lack of a defined theme in the makeStyles for @mui/styles sets it apart from @material-ui/core

Struggling to update my material-ui from version 4.11 to version 5 and running into problems with themes. import { createTheme } from '@mui/material/styles'; import { ThemeProvider, StyledEngineProvider, } from '@mui/material/styles&apo ...

Instructions on how to create a custom datepicker in material ui that opens when a textfield is

I need to implement a functionality where my custom datepicker opens up when the user clicks on a specific textField. Below is the code for my textfield : <TextField InputLabelProps={{ classes: { root: classes.cssLabel, ...

Utilizing React-hook-Form to transfer data between two SelectBoxes

This simple logic is causing me some trouble. Despite using react-hook-form, I thought this would be easy. However, after struggling with it for over a week, I'm still facing challenges. I'm incorporating nextUI components into my project. < ...

Incorrect rendering of the <li> tag

I've been working on creating a simple web "to do list" but I've encountered an issue. When I manually add todos and click on them, the 'text-decoration: line-through;' property is ignored, and I can't see the strikethrough effect ...

I am looking to extract solely the numerical values

Programming Tools ・ react ・ typescript ・ yarn I am trying to extract only numbers using the match method But I keep encountering an error Error Message: TypeError: Cannot read property 'match' of undefined const age="19 years ...

Allow only specific inner divs to dictate the width of the outer div

I'm working with the following HTML structure: <div id="container"> <div id="block1"> <img src="someimage/path" /> </div> <div id="block2"> Some Text </div> <div id="block3"&g ...

Importing .js files from the static folder in Nuxt.js: a step-by-step guide

I'm in the process of transitioning my website, which is currently built using html/css/js, to Nuxt.js so that I can automatically update it from an API. To maintain the same website structure, I have broken down my code into components and imported ...

How to retrieve data in a server-side module

Currently, I am utilizing NextJS 13 with the App Router, along with Prisma for database management. Initially, I began incorporating Prisma queries directly in server-side components rather than creating a separate endpoint in the API and fetching from the ...

Aligning text in the middle of two divs within a header

Screenshot Is there a way to keep the h4 text centered between two divs? I want it to stay static regardless of screen resolution. Currently, the icon and form remain in place but the h4 text moves. How can I ensure that it stays in one spot? <!doctyp ...

What is the method for transmitting a concealed attribute "dragable" to my component?

Currently, I have successfully integrated a here map into my project, but I am now tackling the challenge of adding draggable markers to this map. To achieve this, I am utilizing a custom package/module developed by my company. This package is designed to ...

Accordion menu with smooth CSS3 transitions

I created a unique accordion menu to replace the select form control, and I am interested in using CSS3 transitions to give it a smooth expand and contract effect. Feel free to check out my work on jsfiddle: http://jsfiddle.net/hKsCD/4/ In order to achi ...

Is it possible to modify the background color of a checkbox?

I am looking to modify the background color of the checkbox itself, specifically the white square. I have spent a lot of time researching this topic but most articles suggest creating a div and changing its background color, which does not affect the whi ...

Focus on an empty <input> tag with just the type attribute

In what way can React Testing Library be utilized to isolate a blank <input> element that solely possesses a type attribute? For instance, consider an input field that will eventually have attributes added dynamically, much like the surrounding labe ...

Utilizing the after pseudo element for an active selector in CSS

I'm struggling to make an active icon selector work with the after pseudo element. Here is the code I have attempted: <html> <head> <style type="text/css"> .btn{ width:25%; } .name{ background: #fff; color: #000; text-alig ...

Only one div is revealed by Jquery show and hide, while the other remains hidden

I'm attempting to utilize a single href link to toggle the visibility of two other divs. The first div should be visible by default, while the second div remains hidden. <a href="#ben1" class="fa fa fa-times closer" > <p> clickab ...

The utilization of CSS variables within intricate properties

Imagine having a CSS property called box-shadow: box-shadow: 5px 5px 0 #ccc; What if there is a need to create a variable from the color #ccc? While in SCSS, you could accomplish this with code like: $grey: #ccc; .element { box-shadow: 5px 5px 0 $gre ...

I'm having trouble centering the links in my navigation bar using flexbox, and I'm not sure how to fix it

Struggling with creating a navigation bar for my portfolio-building project. The "Who needs a quote" element is correctly displaying on the left, but I can't figure out how to center align the links "Sports, business, politics". Tried using flexbox op ...

Developing several sliders and ensuring they operate independently of each other

I am currently in the process of developing multiple sliders for a website that I am building. As I reach the halfway point, I have encountered a problem that has stumped me. With several sliders involved, I have successfully obtained the length or count ...

MUI: Interaction with a button inside a MenuItem when not interacted with MenuItem itself?

Currently, I am utilizing MUI's Menu / MenuItem to create a menu of missions / tasks similar to the screenshot below: The MenuItem is interactive: // ... other code <MenuItem value={mission.issueIdentifierId} sx={{px: ...

Updating borderWidth dynamically in react native fails to produce the desired effect

Here is the code I am working with: const [focused, setFocused] = useState(false); <TextInput style={{ ...styles.inputStyles, borderColor: `${focused ? colors.darkPurple : "#b8b8b850"}`, borderWidth: `${focused ? 3 : 1}`, }} placeh ...