22

I have understood the concept of CSS modules so much that I am convinced that I do not want to do anything else that that for the future.

Currently I am trying to refactor an existing app to use CSS modules, the app has used classic sass with BEM methodology since.

Before I describe my problem I want to make clear that I undestand that I am addressing an issue that is not really within the domain of CSS modules. One should apply styles solely for usage inside a single module. At the most one should compose CSS classes with other CSS classes of other modules. But basically: You build an (HTML-)module and you use CSS modules to style that module and that's that.

Here's the problem: In the process of refactoring there is one single issue that derives from having had a SASS-based style system. I can't find a valid method to work with a CSS class within a CSS modules environment when this class should work in combination of another class from another module.

Example in SASS:

[page.scss]

.wrapper {
    margin: 0;
}

[headline.scss]

.headline {
    color: green;
}
.wrapper {
    .headline {
        color: orange;
    }
}

As you can see: One module (page) defines a CSS class "wrapper", another module defines a CSS class "headline". And, additionally, the class "headline" should behave a bit differently when placed inside the class "wrapper".

Again, I know that this is not really the domain of CSS modules. But I really would like to know if this is somehow doable with CSS modules? The "composes"-feature of CSS modules does not really fit here...

hurrtz
  • 1,871
  • 1
  • 19
  • 34

2 Answers2

9

This is a common issue when migrating to CSS Modules. In short, a css module cannot override a style from another css module, and this is by design. Styles are supposed to live with the components that render them, and nowhere else.

What you can do to refactor this is to create a component style variant and explicitly set the variant through a prop when rendered within your wrapper.

For example, suppose your headline component currently looks something like this:

CSS

.headline {
  color: green;
}

JSX

import styles from "Headline.css";
const Headline = () => {
  return (
    <div className={styles.headline} />
  );
}

Rather than trying to override the .headline class name from somewhere else, you can create a variant class name that you toggle through a prop:

CSS

.headline-green {
  color: green;
}

.headline-orange {
  color: orange;
}

JSX

import styles from "Headline.css";
const Headline = ({orange}) => {
  return (
    <div className={orange ? styles.headlineOrange : styles.headlineGreen} />
  );
}

And when you render it from your wrapper, set it to the orange variant:

<Headline orange />

Tip: you can use composes to eliminate duplicate common styles between your variants.

Aaron Beall
  • 49,769
  • 26
  • 85
  • 103
  • 15
    I dont like this approach, it leads t ocreating multiple classes when only a small change is need to be done. – exoslav Mar 04 '18 at 09:41
  • @exoslav That's part of the philosophy behind CSS modules, that each class should have all the styles, however there is certainly a counter argument to be made. [This is an interesting (and short) thread.](https://github.com/css-modules/css-modules/issues/63) CSS modules doesn't stop you from using multiple classes in any way, though, that's really up to you. This example is just the way CSS Modules would recommend doing it. – Aaron Beall Mar 05 '18 at 15:33
  • 1
    Philosophy is nice, and it even make sense in this case, however, I have a legacy codebase on my hand that was not built by philosophers, and it's be good to be able to move it to modules. Is there a way to actually reference classes from other modules? – deadalnix Feb 27 '22 at 20:27
  • 1
    @deadalnix Only if you mark them as [`:global()`](https://github.com/css-modules/css-modules#exceptions) – Aaron Beall Mar 29 '22 at 13:55
  • @AaronBeall, how can it handles contextual styling? i.e. `.form .button { ... }`. The button will have a different look within a form. That information should not be known by the component, but the CSS needs to know it. – unional Mar 29 '22 at 17:11
2

You could use :global, to change the .headline class inside the .wrapper class:

.wrapper {
    :global(.headline) {
        color: orange;
    }
}
kevin parra
  • 336
  • 4
  • 11