Search code examples
cssreactjsnext.jsstyles

Styled components, two layers of className - How would I apply style in component declaration?


I have created a Container component with component styles in next.js. When I declare use of this container component throughout my site, I would like to add a className to it and subjectively style it depending on the context of its use.

Here is an example of my 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;

So, I want to give it a maximum width of 1200px, and centre it with auto margins. No problem, I have done that.

Now, I am planning to use this component in the header of my site. But in the case of the header, I would like the Container component to be 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;

When I view the site, I noticed the flexbox style I specified for the Container component in the header is not present.

I was expecting the className to take effect, and allow me to add additional styles.

I believe this has something to do with it thinking that className is not a class name, rather props. But, I want to keep my code dry by creating style inheritance on components.

How could I do this?

Thanks for the help!


Solution

  • I believe I have found the answer to my own question (I will still leave this question open for a couple more days just in case it can be improved).

    In order to pass styles, you can add the "global" flag to the styled JSX and append additional classnames in the component with props.className.

    Parent Container component using 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;
    

    Then, when you want to use that component, you can add additional styles with the global flag in the <style jsx>:

    Container being used and styled even more in 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;
    

    This is not 100% perfect though (but in my opinion it is still pretty good):

    • The global flag makes your styles global. So other components can use these styles (I believe)
    • You need to make sure your components take in props.className to append additional classnames for this global style