2
votes

I'm using create-react-app latest version 2.1.3. I've created a demo app to test css modules, that in create-react-app 2.1.3 should be out-of-the-box with no need to run "npm eject" or perform config file modifications. But for some reason, styles that are declared in the App css-module file override styles that are declared in a child component css-module file.

I use the generated App.js as a component that embed another child component called Person.js (that implements a person card). Both components use css-modules and have their own corresponding App.module.css and Person.module.css css files. both components have button elements with their unique styles from their css-module. but when i run the app, i can see in chrome developer tools that Person's button style is strike-through and disabled by the button class declared in the App.module.css file and i can't understand why. the whole purpose of css-module is to declare css styles only to the component that imports them.

App.js

import React, { Component } from "react";
import Person from "./Person/Person";
import styles from "./App.module.css";

class App extends Component {
   state = {
   persons: [
      { id: "abcd", name: "John Do", age: 41 }
   ],
   someOtherState: "Some other state",
   showPersons: false
  };

  togglePersonsHandler = () => {
    this.setState({
      showPersons: !this.state.showPersons
    });
  };

  render() {
    let persons = null;
    let btnClass = "";
    if (this.state.showPersons && this.state.persons.length > 0) {
      persons = (
        <div>
          {this.state.persons.map((person, index) => {
            return (
              <Person
                key={person.id}
                name={person.name}
                age={person.age}
              />
            );
          })}
        </div>
      );

      btnClass = styles.red;
    }

    const classes = [];
    if (this.state.persons.length <= 2) {
      classes.push(styles.red);
    }

    if (this.state.persons.length <= 1) {
      classes.push(styles.bold);
    }

    return (
      <div className={styles.App}>
        <h1> Hi, I'm a react app </h1>
        <p className={classes.join(" ")}>This is a paragraph!!!</p>
        <button
          className={btnClass}
          onClick={this.togglePersonsHandler} 
        >
          Toggle Persons
        </button>
        {persons}
      </div>
    );
   }
}

export default App;

App.module.css

.App {
  text-align: center;
}

.red {
  color: red;
}

.bold {
  font-weight: bold;
}

.App button {
  background-color: green;
  color: white;
  font: inherit;
  border: 1px solid blue;
  padding: 8px;
  cursor: pointer;
}

Person.js

import React from "react";
import styles from "./Person.module.css";

const person = props => {
  return (
    <div className={styles.Person}>
      <p onClick={props.click}>
        I'm {props.name} and i'm {props.age} years old.
      </p>
      <p>{props.children}</p>
      <input type="text" onChange={props.changed} value={props.name} />
      <button className={styles.personBtn}>Click Me</button>
    </div>
  );
};

Person.module.css

.Person {
  width: 60%;
  margin: 16px auto;
  border: 1px solid #eee;
  box-shadow: 0 2px 3px #ccc;
  padding: 16px;
  text-align: center;
}

.personBtn {
  background-color: blue;
}

I expect that the button inside Person component should have blue background-color as defined in Person.module.css, but the actual result is that they get the App.module.css .App button style (i.e. green background)

chrome dev tools to illustrate the problem

1

1 Answers

0
votes

You just need to add query: { modules: true } in css-loader to use it as CSS Modules in your webpack.config.js like this example

webpack.config.js

const path = require("path");

module.exports = {
  entry: ["./src/whatever.js"],

  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "engine.js"
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /(node_modules)/,
        query: {
          presets: ["es2015", "stage-2"]
        }
      },
      {
        test: /\.css$/,
        loader: "style-loader"
      },
      {
        test: /\.css$/,
        loader: "css-loader",
        query: {
          modules: true
        }
      }
    ]
  }
};