CSS modules

Scope styles by default and avoid naming collisions across extension pages, options UIs, and popups.

Extension.js supports CSS Modules with zero configuration for module-style filenames and uses the Rspack CSS pipeline under the hood.

When CSS modules are a good fit

  • You need local class scoping without adopting a full CSS-in-JS stack.
  • You share components across popup/options/new-tab surfaces.
  • You want predictable style ownership in larger extension codebases.

Template examples

content-css-modules

content-css-modules template screenshot

Add locally scoped styles to content-script UI with minimal setup.

npm
pnpm
yarn
npx extension@latest create my-extension --template=content-css-modules

Repository: extension-js/examples/content-css-modules

Usage with an existing extension

To use CSS Modules, name files with a module suffix:

  • *.module.css
  • *.module.scss
  • *.module.sass
  • *.module.less

Use the related language pages for Sass and Less setup requirements.

- myComponentCss.css
+ myComponentCss.module.css

Usage example

After renaming your stylesheet, import and use it in your component:

import styles from "./styles/myComponent.module.css";

const button = document.createElement("button");
button.className = styles.primary;
button.innerText = "Click here";
document.body.appendChild(button);

How it works

Extension.js enables Rspack CSS support and handles module imports through the CSS module pipeline:

  • default import style maps (import styles from "./x.module.css")
  • class names are generated through Rspack CSS module generation
  • module class exports are designed for direct use in JS/TS/TSX files

In extension page contexts (for example popup/options/new tab), module imports behave as expected with hashed/localized class mapping.

Content script note

Content script styles use an asset-based CSS flow. In that context, CSS is emitted and injected as stylesheet content rather than consumed as CSS Module JS exports.

Use component-level local class naming in content scripts, and avoid assuming module export maps there unless your setup explicitly verifies that path.

React/Preact example usage

For React or Preact, you can import and use the CSS Module in the component like this:

import styles from "./styles/myComponent.module.css";

export default function NewTabPage() {
  return <button className={styles.primary}>Click here</button>;
}

Vue example usage

In Vue, you can use module classes from SFC styles:

<template>
  <button :class="$style.primary">Click here</button>
</template>

<style module>
@import "./styles/myComponent.module.css";
</style>

Svelte example usage

In Svelte, import module mappings and apply class names:

<script>
  import styles from "./styles/myComponent.module.css";
</script>

<button class={styles.primary}>Click here</button>

Best practices

  • Keep module styles close to components (Component.module.css) for easier ownership.
  • Use :global(...) sparingly and only for intentional global overrides.
  • Prefer module styles for extension pages and framework components where class mapping is explicit.

Next steps

Video walkthrough

Video demo soon: css modules extension workflow