Search code examples
cssreactjscss-modulesreact-css-modules

How to use nested css class (cascade) with React CSS Modules


I did see a lot of similar questions on SO but at end, it seems that my issue is a bit different..

I have a react project where (for some reason) I want two types of CSS loading:

  • Some global (imported from main.tsx as import 'assets/global.css';)
  • Some scoped (imported from a component as import style from './style.module.css';)

The global ones works as expected, it's the module one that are weird.. If I want to style a simple <a></a> within a div, this following works:

copyrights

.copyrights a { // as Link is rendered as a `<a></a>`
  text-decoration: none;
}


/*...*/
import style from './style.module.css';

export const CopyrightsComponent = () => {
  return (
    <Container className={style.copyrights}>
      <Row className={`justify-content-center`}>
        <p>
          {COPYRIGHTS_TEXT}
          <Link to={TERMS_OF_USE_ROUTE_ROUTE}>{COPYRIGHTS_TERMS_OF_USE_HYPERLINK}</Link>
          <Link to={TERMS_OF_USE_ROUTE_ROUTE}>{COPYRIGHTS_PRIVACY_POLICIES_HYPERLINK}</Link>
        </p>
      </Row>
    </Container>
  );
};

export default CopyrightsComponent;

HOWEVER! When trying to nest CSS in order to select the right child (like a specific img within a certain div), it doesn't work.. I don't understand why

foo

.foo .bar1 a {
  text-decoration: none;
}
.foo .bar2 a {
  color: red;
}

/*...*/
import style from './style.module.css';

export const FooComponent = () => {
  return (
    <div className{style.foo}>
      <div className{style.bar1}>
        <a>bar 1</a>
      </div>
      <div className{style.bar2}>
        <a>bar 2</a>
      </div>
    </div>
  );
};

export default FooComponent;

Thanks for any help...


Solution

  • This doesen't work since your .bar class is scoped to the element.

    It should work, if you reduce the specificity of the selector to either:

    .foo div a
    

    or,

    .bar a
    

    When you utilize CSS modules, and you link your class directly to an element - the class name becomes unique, since obfuscation is appended to the class name, as per the CSS modules spec (It is scoped to the element). You can see this by inspecting a DOM element that you have linked to a class with this technique; It looks something like this: component_name-module--class_name--eq-vo.

    Because of this, when you try to chain custom selectors like you did originally, the middle part of the selector (.bar) doesen't exist in its original simplicity because of this obfuscation.