CSS Modules & ReactJS: Parent and child CSS classes in different components
Asked Answered
R

6

15

So I am building a react application and have a quick question. If I have two separate components: and with CSS classes navigation.css and navigationLogo.css respectively. In navigation.css I have a class named .main and in navigationLogo.css I want to have a class like so:

.main .main_in_logo {
 color: red;
}

But with CSS Modules I am unable to do this, any ideas on a work around?

Reeva answered 12/2, 2017 at 18:43 Comment(0)
D
1

The child component should not have a css rule that is dependent upon the parent css classname.

the child should just be:

.main_in_logo { color: red; }

If you need to define styles that involve both parent and child, then the easiest way is to define the styles completely in the parent:

/* navigation.css */
.main .main_in_logo {
   color: red;
}

Then have the parent pass the css class to the child and tell the child to use it:

// Navigation.js
<NavigationLogo className={navigationCss.main_in_logo} />

// NavigationLogo.js
<div className={"foo " + this.props.className}>stuff</div>
Dobbins answered 12/2, 2017 at 20:17 Comment(4)
What about nested classes? if we had .main .main_in_logo .anotherClassInside... The css of anotherClassInside won't ever be applied. How do you style other nested classes from the parent?Cartel
Parent component passes a className prop (or multiple props like headerClassName and bodyClassName) to the child component and the child component adds that className to their elements. Now the parent can add styling in its css file based upon the classname it is passing to the child componentsDobbins
That would work, but wouldn't scale at all... That's the point of my question.Cartel
You should probably post a new question about how to do it as scale with an example of the scale you are talking aboutDobbins
H
31

I just feel that the explanations here are not complete enough. In css you do .parentSelector .childSelector in order to select the child. The same rule is for css modules, but in your html/jsx you should add to the parent and the child the relevant className -> styles.parentSelector , styles.childSelector.

<div className={styles.container}>text</div>

This way you can have in your css something like:

.banner .container{
background-color:reb;
}
.banner .container{
background-color:blue;
}

Sometimes you use libraries and you want to change something somewhere down the DOM inside the library and you can't change its source code. In this case you can use the :global like this:

.parentElement :global(div)
.parentElement :global(#some-lib-element-selector)
Halfbreed answered 12/10, 2021 at 13:36 Comment(1)
:global() worked perfectly for me when I needed to change styles in a child component from a third party module but did not want to use a global stylesheet.Loraine
T
14

I was looking for the same problem and didn't find the solution here, maybe because the post is 3 years old. The accepted answer is, in my opinion but not mine only, not scalable.

I don't really know if this is something new, but I found out what I would do in vanilla CSS adapted to CSS modules.

Here is what I did and fully suits my needs:


/* parent.css */
.main {
   ...some CSS...
}

/* logo.css */
@value main from "./parent.css";

.logo {
   ...some CSS...
}

.main .logo {
   color: red
}

Here, we are using @value, which is a CSS modules variable and allows us to bind with another file to build a selector including the final name of the parent "main".

As strange as it looks to me, it took some time to find out about this solution, I hope this will save some time and help other people!

Tejada answered 13/4, 2021 at 20:3 Comment(2)
exactly what i needed! Fantastic, thank you.Meanly
Worked for me like a charm also. Kudos @TejadaYarrow
E
1

Why you need to create .main .main_in_logo - the main idea of styles with parent elements its not to broke your css with other styles in the future. But its impossible with css modules, because your styles will be unique forever.

But even you really need it you can use global css for these 2 components - documentation about global css for react-css-modules.

Ettaettari answered 12/2, 2017 at 20:6 Comment(0)
D
1

The child component should not have a css rule that is dependent upon the parent css classname.

the child should just be:

.main_in_logo { color: red; }

If you need to define styles that involve both parent and child, then the easiest way is to define the styles completely in the parent:

/* navigation.css */
.main .main_in_logo {
   color: red;
}

Then have the parent pass the css class to the child and tell the child to use it:

// Navigation.js
<NavigationLogo className={navigationCss.main_in_logo} />

// NavigationLogo.js
<div className={"foo " + this.props.className}>stuff</div>
Dobbins answered 12/2, 2017 at 20:17 Comment(4)
What about nested classes? if we had .main .main_in_logo .anotherClassInside... The css of anotherClassInside won't ever be applied. How do you style other nested classes from the parent?Cartel
Parent component passes a className prop (or multiple props like headerClassName and bodyClassName) to the child component and the child component adds that className to their elements. Now the parent can add styling in its css file based upon the classname it is passing to the child componentsDobbins
That would work, but wouldn't scale at all... That's the point of my question.Cartel
You should probably post a new question about how to do it as scale with an example of the scale you are talking aboutDobbins
B
0

You don't need to be specify which child class you are referring to when using CSS modules in ReactjS.

so doing:

.main_in_logo {
     color: red;
}

will be enough in the stylesheet.

Bradfordbradlee answered 26/7, 2018 at 15:13 Comment(0)
B
0

I ended up using CSS the normal way but with BEM convention.

I mean after all, what the CSS modules do is adding the [this_name].module.css to your css classes anyway. If you typed it correctly in the first place, there's no need of using this. It's just a new abstract that allow newbies so they can just do stuff without having to worry about class names clashing.

// Main.jsx
import './Main.css'
import Logo from './Logo.jsx'

const Main = () => {
  return (
    <div className="main">
      <Logo className="main__logo" />
    </div>
  )
}
/* Main.css */
.main {/* do magic */}
.main__logo {/* do magic but for Logo component */}

So maybe you had Logo component like this..

// Logo.jsx
import './Logo.css'

const Logo = () => {
  return (
    <div className="logo">
      <img className="logo__img" />
    </div>
  )
}
/* Logo.css */
.logo {/* do magic for logo */}
.logo__img {/* do magic for logo's image */}

This feels much more natural.

Beatty answered 11/8, 2022 at 9:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.