skip to Main Content

I have a component that gets rendered in multiple places. This component will need to have different text color depending on where it gets rendered.

My approach to building the component is to accept a classNames prop so that I can pass in custom css where ever the component is rendered.

Header.js

export const Header = ({ classNames, lightMode = true, menuIconColor }) => {
  const navigate = useNavigate();
  const { isNavOpen, setIsNavOpen } = useContext(NavigationContext);

  return (
    <div className={styles.header}>
      <div
        className={cx(styles.navBar, classNames, {
          [styles["navBar--hidden"]]: isNavOpen,
        })}
      >
        <a className={styles.logoNav}>
            <img
              className={styles.logo}
              src={LogoWithTextLight}
            /> 
        </a>
        <div className={styles.navButtons}>
          <button className={styles.navButton} onClick={() => navigate("/")}>
            HOME
          </button>
          <button
            className={styles.navButton}
            onClick={() => navigate("/learn")}
          >
            LEARN
          </button>
          <button
            className={styles.navButton}
            onClick={() => navigate("/about")}
          >
            ABOUT
          </button>
        </div>
      </div>
    </div>
  );
};

The header.js file imports styles from ./header.module.scss

This approach works well for passing styles that affect the <div className={styles.header}>. However I am not able to pass in nested styles to change the styles of divs nested deeper.

For example I want to pass in css that changes the color of the text onHover.

So when I render my header component on my learn page I pass a css className.

<Header classNames={styles.header} lightMode={false} />

The learn page imports styles from ./learn.module.scss.

Inside my learn.module.scss file I have:

  .header {
    color: rgb(9, 98, 8);

    .navBar {
      .navButtons {
        .navButton {
          color: inherit;
          font-size: inherit;
          font-weight: inherit;

          &:hover {
            color: black;
          }
        }
      }
    }
  }

This works to successfully override the header.module.scss header class style. However the hover style is not being applied. Additionally I am not able to do any styling directly on the navButton class.

2

Answers


  1. The reason why your styling doesnt show is due to how scss modules work.

    When you inherit classes in this way, your parent class selector (.navButton in learn.module.scss) tries to match the child components scss resolved class name eg .navButton__4jxl.

    You can solve this in two ways:

    1. Dont inherit styling, instead inherit props telling the component which ”local” class names to render.

    2. The hacky way. Use wildcard css selectors to target parts of class names, effectivly ignoring the scss module appended part.

    E.g.
    [class^=”navButton”] {

    }

    Solution 2 gets messy quick and i dont recommend it.

    I tried the wildcard classnames solution in a previous project. I realized my mistake and refactored into inheriting non-css props (solution 1.)

    Hope this helps!

    Login or Signup to reply.
  2. I would solve this by introducing css variables in the styling for the re-usable component to allow customization; and gradually expanding the API surface as needed.

    Here’s an example:

    // styling for Header component
    // supports: --nav-item-color
    //           --nav-item-background
    //           --nav-item-hover-color
    //           --nav-item-hover-background
    // using the private custom css property pattern
    // https://lea.verou.me/2021/10/custom-properties-with-defaults/
    
    .header {
      --_nav-item-color: var(--nav-item-color, #{$primary-color});
      --_nav-item-background: var(--nav-item-background, #{$primary-color-contrast});
      --_nav-item-hover-color: var(--nav-item-hover-color, #{$primary-color-light});
      --_nav-item-hover-background: var(--nav-item-hover-background, #{$primary-color-contrast});
    
      .navBar { ... }
      .navButtons { ... }
      .navButton {
        color: var(--_nav-item-color);
        background: var(--_nav-item-background);
    
        &:hover {
          color: var(--_nav-item-hover-color);
          background: var(--_nav-item-hover-background);
        }
      }
    }
    

    and when you need to customize it

    .special-header {
      --nav-item-hover-color: black;
    }
    
      <Header className={style.specialHeader} />
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search