Search code examples
reactjsnext.jssassstyled-components

Styling nextJs component module - embedded styles wont work


We use currently the latest nextJs (v14) with react (v18). I tried to use the nextJs module css (note: it works with scss however the documentation does not mention it). But found some limitations working with it:

.toastSuccess {
  color: green;
  .undo {
    color: blue;
  }
}

.toastError {
  color: red;
  .undo {
    color: blue;
  }
}

When I import it to .tsx file, and tries to apply it does not work:

import styles from "./toast.module.scss";

return (
 <div className={isSuccess ? styles.toastSuccess : styles.toastError}>
   <div className="undo">undo</div>
   ...
   </div>
 </div>
)

Now I'm just wondering what the best approach in is 2024 storing and applying styles in a "huge" react nextJs project. What I found is:

  1. do not make styles at all, but combine them from small parts (don't know the official name of this method, but as bootstrap or tailwind: className="d-flex flex-row m-4"
  2. make a huge collection of unique styles in a style folder and use them
  3. use styled components
  4. use some kind of module styling solution

I think the last is the best, as style definitions come from figma, and it's the best to store them separately from the .tsx file (but close to it). Also guarantees the style names uniqueness and that each modification has a little and calculatable impact. But this nextjs module styling solution seems not the best.

Any different approach, or some solution which works better than this one?


Solution

  • To elaboratte on my answer: For atomic/molecules I wouldnt use normal classes, those are only for more complex components like your navbar or for example a product display. Using styled components I would do:

    
    const Component = styled((props) => {
      return <div {...props}>
        <div class="header" />
        <div class="content" />
      </div>
    })`
    
    display: grid;
    grid-template: 200px 1fr / 1fr;
    
    & > .header {
      // .header styles
    }
    
    & > .content {
      // .content stlyes
    }
    
    `;
    

    For more complex components you can stick to full SC className generation but I have also done some apps and found that classname collision was never that big of a problem and using only SC components or modules for every className feels cumbersome.

    
    const TextInner = styled.span``;
    
    const Text = styled((props) => {
      const {component: Component = "p", ...rest} = props;
      return <Component {...rest}>
        <TextInner>{children}</TextInner>
      </Component>
    })`
    
      ${TextInner} {}
    `;