What is the most effective method to override parent styles while utilizing CSS Modules?

I'm currently using NextJS along with CSS Modules for styling purposes.

One of my goals is to adjust the appearance of a component in different scenarios:

  1. When it's rendered normally on a page, utilizing props to specify className modifiers.
  2. When it's rendered within a specific parent component.
  3. When it's rendered within a specific parent component as props.children.

I have solutions working for all these scenarios, but I'm wondering if any of these methods are considered bad practice or if there might be better alternatives to explore (especially for scenario 3).

For example, let's consider a simple Button component:

Scenario 1:

button.module.scss

.button {
   color: 'black';
}

.red {
   color: 'red';
}

.blue {
   color: 'blue';
}

Button.jsx

import styles from './button.module.scss';

const Button = (props) => {

   const classNames = [styles.button];

   props.modifiers.map((modifier) => {
      classNames.push(styles[modifier]);
   });

   return (
      <button className={classNames.join(' ')}>{props.text}</button>
   );
}

export default Button;

Page.jsx

<Button text={`Test`}/>
<Button text={`Test`} modifiers={[`red`]}/>
<Button text={`Test`} blue={[`red`]}//>

Scenario 2:

Now, imagine needing to change the styling of the Button component when it's placed inside ParentComponent (and potentially combined with the previous method).

parent-component.module.scss

.button {
   background-color: 'green';
}

ParentComponent.jsx

import styles from './parent-component.module.scss';
import Button from 'components/button/Button.jsx';

const ParentComponent = (props) => {
   return (
      <>
         <Button text={`Test`} modifiers={[styles.button}>
         <Button text={`Test`} modifiers={[`red`, styles.button]}>
      </>
   );
}

Button.jsx needs updating to handle this new requirement:

props.modifiers.map((modifier) => {
   classNames.push(styles[modifier] || modifier);
});

Scenario 3:

ParentComponent.jsx

import styles from './parent-component.module.scss';

const ParentComponent = (props) => {
   return (
      <div>{props.children}</div>
   );
}

// Expose styles on the exported component so we can reference them in page.jsx
ParentComponent.styles = styles;

export default ParentComponent;

Page.jsx

<ParentComponent>
   <Button text={`Test`} modifiers={[ParentComponent.styles.button]}>
</ParentComponent>

My background is in BEM, where I typically use a technique like the following to address similar challenges: Source

.component {
  $self: &;
  display: block;
  max-width: 30rem;
  min-height: 30rem;
  
  &--reversed {
    background: white;
    border-color: lightgray;
    
    #{ $self }__child-element {
      background: rebeccapurple;
    }
  }
}

Any advice or suggestions would be greatly appreciated.

Answer №1

Utilize the npm module known as classnames.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

npm fails during the build process due to webpack issues

I find myself lost in trying to pinpoint the right question to ask, but I am encountering a failure while running npm run build. > <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="395a5655564b14564b5e585750435c4b790817091709" ...

Serializing data in Next.js with MongoDB integration

Having trouble loading data from mongodb into nextjs and encountering a persistent error. The data has been added to the database using Python pymongo. SerializableError: Error serializing .jobs[0] returned from getServerSideProps in "/". Reaso ...

Displaying divs of varying heights in a line

I'm facing a challenge in creating floating divs, just like illustrated in the image provided in the link below. Currently, I am employing the float left property to align all the divs next to each other. The first picture displays the default layout ...

What sets fragments apart from strict mode?

Can you explain the key distinctions, beyond the obvious ones, between fragment and strict mode? ...

Send the user to the appropriate subdomain within a ReactJs application

I'm currently working on a React website project where I want to assign a unique subdomain to each user after they sign up based on the username they input. For example, if their username is john, then their subdomain would be john.mydomain.com. I&ap ...

Adjust parent div size based on image size increase

I am currently facing a situation where I have a page displaying an image, but sometimes it appears too small. In order to make the image larger, I have utilized CSS Transform and it is working well. However, the issue lies in the fact that the parent DIV ...

Building an easy-to-use jQuery task list

I'm currently working on a basic to-do list in Javascript, but I've encountered an issue. When I check the checkbox, the style of the adjacent text doesn't change as expected. Instead, it's the heading text that is affected by the chang ...

Having trouble getting CSS3 Keyframes to function properly?

Check out the following code snippet: .startanimation { height: 100px; width: 100px; background: yellow; -webkit-animation: animate 1s infinite; } @-webkit-keyframes animate { 100% { width: 300px; height: 300px; } ...

Approach to Using Bootstrap 4 with Intl-Tel-Input

I've been attempting to integrate intl-tel-input with bootstrap 4, but I'm facing an issue where the placeholder for the input is not showing up. I've tried various solutions found online, but none of them seem to work. Here's my HTML ...

the stacking context of elements with z-index and relative positioning

I am currently working on a modal that is toggled using JavaScript. Within the modal, I am dynamically adding an image using JavaScript. Additionally, there will be a div element overlaying the image to simulate cropping (extract coordinates from the imag ...

Difficulty rendering Radio Group component in React with Material UI

Within my React state, I have an options object structured like this: { "0": ["Peru", "Brazil", "Colombia", "Ecuador"], "1": ["False", "True"], "2": ["Kurdi ...

Just starting out with JavaScript - updating the appearance of an element

Based on the value of a boolean, I am looking to control the visibility of specific tabs in my sidebar when the page loads. var someVar = true; function show_ifTrue() { if (Boolean(someVar) == true) { document.getElementById('x'). ...

Having trouble with your Bootstrap 4 Dropdown Menu?

I attempted to implement the dropdown menu example from Bootstrap 4, but unfortunately it does not seem to be working as expected. The dropdown menu does not appear when clicked. <li class="nav-item dropdown"> <a class="nav-link dropdown-to ...

Error: Unable to access the 'offsetTop' property of null

I attempted to implement a scroll effect in my project. The goal was for users to be taken to a specific section when they clicked on an option in the navbar. However, I encountered an error during implementation. Below is the code snippet where the error ...

Two divisions inside another "wrapper" division - Adjusting the width

I'm facing an issue with my CSS. I have a container div "container" that contains two other divs - "left" and "main". The width of the container is set to 90% of the body's width, with a margin of 3% auto to center it. .container{ margin:3% auto ...

Maintain scrolling at the bottom with React.js

Is there a way to make a div element increase in height through an animation without extending beyond the viewable area, causing the window to automatically scroll down as the div expands? I am looking for a solution that will keep the scroll position lock ...

Is there a way to conceal one column in a row and display only the second column from a medium screen to a small screen using Bootstrap 5?

I am currently working on creating a row with two columns, one being the left_bar column and the other a large image. My goal is to display only the large image (column 2) when the screen size changes from medium to small breakpoints, hiding the left_bar c ...

Exploring MaterialUI withStyles to customize disabled switches with a CSS override

As I work on my project using React and MaterialUI, I've encountered a problem with customizing inputs. Despite trying various selectors, I can't seem to change the black color of this particular input. It would be helpful to have a clearer way o ...

Building a server-side rendering application with NextJS, incorporating Redux Toolkit Query and authentication token functionality

Following instructions from the documentation, I have set up a base query for sending headers, specifically for authentication purposes. const baseQuery = fetchBaseQuery({ baseUrl: '/', prepareHeaders: (headers, { getState }) => { cons ...

The technique of binding methods in React

When working with React.js, it's recommended to define your method binding in the constructor for better performance. Here's an example: constructor(props){ this.someFunction = this.someFunction.bind(this); } This approach is more efficient t ...