42

I'm busy learning React with CSS-Modules and I don't quite understand how one would store variables? For example, in Sass you're able to do this:

// _variables.scss
$primary-color: #f1f1f1; 

// heading.scss
@import './variables';
.heading {
  color: $primary-color
}

How do you achieve this in CSS Modules?

5 Answers 5

73

This is how you do it with vanilla CSS Modules

// vars.css
:root {
  --color-black: #222;
}


// myComponent.module.css
@import './vars.css';

.component {
  color: var(--color-black);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Note that this will only work if you configure with dashed indents set to false if you use lightningcss or perhaps some other processors (lightningcss.dev/css-modules.html). cssModules: { dashedIdents: false }
23

The CSS-Modules documentation mentions variables here: https://github.com/css-modules/css-modules/blob/master/docs/values-variables.md

With this you can import variables as so:

@value colors: "../../main/colors.css";
@value primary, secondary, tertiary from colors;

which can be used in your css:

.main {
    background-color: tertiary;
    border-top: 30px solid primary;
}

To make this work postcss-loader and postcss-modules-values need to be added to your webpack config. See below:

        {
            test: /\.css$/,
            use: [{
                    loader: 'style-loader'
                },
                {
                    loader: 'css-loader',
                    options: {
                        modules: true,
                        localIdentName: '[name]_[local]_[hash:base64:5]'
                    }
                },
                {
                    loader: 'postcss-loader',
                    options: {
                        plugins: [postcssModulesValues]
                    }
                }
            ]
        }

2 Comments

localIdentName has now moved inside modules. You may wanna do: modules: {auto: true, localIdentName: "[name]_[local]_[hash:base64:5]",}
Any idea how a @value can be used in a CSS calc() ? For example this throws and error: "@value margin: 10px; .someclass{ width: calc(100% - margin); }"
9

One way could be to use dependencies. For example,

// variables.css
.primaryColor {
  color: #f1f1f1
}

// heading.css
.heading {
  composes: primaryColor from "./variables.css"
}

See more detailed information here: https://github.com/css-modules/css-modules#dependencies

If you're using webpack there are more examples here: https://github.com/webpack/css-loader#composing-css-classes

Also if you are using webpack you can still use Sass with CSS modules.

3 Comments

While composition is an option, I would advise following Icharbon's answer. With postcss you have actual variable support, and will help keep code DRY'er. CSS Modules and Sass can be used together though, so I'd prefer Sass variables over the @Value syntax mentioned.
composition !== variables.
While this works for this example, this answer is not the answer to the question "how can you use global values with css modules" haha. For example, what if I wanted to use this color for the background color as well as color?
6

If you add the root css variables in index.css you can access these globally without using @import

This is assuming that index.css is imported in the src/App.js file as the default file structure.

css modules are scoped meaning that the variables inside them are local, but that does not mean you cannot access variables from a global css file.

Example One

Let's say this is our index.css

:root {
  --header-width: 95vw;
  --border-radius-one: 5px;
}
body {
  background-color: #261d54;
  margin: 0;
  font-family: "Poppins", sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

We can then access this root css variables like so:

#header {
  margin: 0 auto;
  width: var(--header-width);
  border:1px solid blue;
  border-radius: var(--border-radius-one);
}

Now, if you would like to modify these variables from the script, so that you can make them dynamic you can use the setProperty() JS method to set a new value for a CSS property.

So, the way you would do this in React is by creating a function to change the property and implement an onClick in JSX

Example Two

function changeFontSize(size){
   document.documentElement.setProperty('--font-size', size)
}

return(
  <div>
    <button onClick={() => changeFontSize('18px')}>
      set font size to 18px
    </button>
    <button onClick={() => changeFontSize('12px')}>
      set font size to 12px
    </button>
  </div>
)

If you want to read about documentElement go here.

Comments

1

You really don't have to do anything fancy to use CSS Variables in CSS modules.

app/global.css

html {
  --test-color: red;
}

app/layout.tsx

import './globals.css' // << The important bit
import { Link } from '@/app/component/Link'

export default function RootLayout({ children }){
  return (
    <>
      <Link href="/">Home</Link>
      {children}
    </>
  )
}

app/component/link.module.css (nothing fancy, this just works)

.linkElem {
  color: var(--test-color);
}

app/component/Link.tsx

import styles from './link.module.css'

export function Link({ children, href }) {
  return (
    <a href={href} className={styles.linkElem}>{children}</a>
  )
}

PS. I disagree with using :root for defining the base variables since html has lower specificity than :root and so is easier to override.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.