Using scss
in NextJS components/modules, the traditional way e.g. by passing the actual classname like a-b-c
instead of styles['a-b-c']
might seem a bit harder than expected. But actually it's supported out of the box. Just the next.config.js
requires a bit of tweaking.
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
webpack(config) {
const rules = config.module.rules.find((rule) => typeof rule.oneOf === 'object').oneOf.filter((rule) => Array.isArray(rule.use));
rules.forEach((rule) => {
rule.use.forEach((loader) => {
// To prevent classname hashing, so that using styles[rootClassName] allows us to
// pick all the other classes embedded under it in the dom, without really doing
// styles[className] everytime.
if (loader.loader?.includes('css-loader') && !loader.loader?.includes('postcss-loader')) {
loader.options.modules.getLocalIdent = (context, _, exportName) => exportName;
}
});
});
return config;
},
};
module.exports = nextConfig;
The example component here is called Agent
which renders a person's name and avatar.
Folder structure-
agent
- agent.tsx
- agent.module.scss
- index.ts
The scss
file content-
// Sample scss
// agent.module.scss
.agent-root {
.agent__name {
font-size: 16px;
line-height: 22px;
color: var(--app-clr-primary-text);
}
.agent__avatar {
border-radius: 50%;
object-fit: contain;
border: 2px solid var(--app-clr-primary-border);
}
...
}
The component code-
// Sample Component
// agent.tsx
import styles from 'agent.module.scss';
const Agent = (props) => {
return (
<div className={styles['agent-root']}>
<p className="agent__name">{props.agentName}</p>
<img className="agent__avatar" src={props.agentAvatar.src}/>
</div>
);
}
As you can see with this simple change in config, now you can only refer the style class root from the scss module style object, and it can refer to all the child classnames automatically - like you would have wanted!