CSS Modules DevToolsClass name completion, go to definition, hover previews and diagnostics for CSS Modules, plus It runs as its own language server and never loads TypeScript, so it behaves the same whichever TS version your workspace uses. It also means nothing runs inside FeaturesClass completionType
Hover previewHovering a class shows all its rules in source order, with their
Go to definitionF12 or Cmd+click on
Missing class and missing file checks
Auto-importType
|
| Setting | Default | What it does |
|---|---|---|
tsx.enabled |
"auto" |
Class features in TS/JS files. auto hands them to css-modules-kit when its TS plugin is active on TypeScript < 7. |
completion.enabled |
true |
Class completion in TS/JS and in composes. |
definition.enabled |
true |
Go to definition for classes, composes and var(). |
hover.enabled |
true |
Hover previews for classes and variables. |
hover.maxLines |
30 |
Longest hover preview before it's cut off. |
autoImport.enabled |
true |
Suggest nearby modules for an unimported styles.. |
autoImport.identifiers |
["styles", "classes", "css", "s"] |
Names that trigger auto-import. An empty list turns it off. |
variables.enabled |
true |
Completion, definition and hover for var(--*). |
variables.tsxStrings |
true |
var(--*) completion inside strings in TS/JS files. |
variables.colors |
true |
Color swatches on var(--*) usages. |
classNameConvention |
"asIs" |
asIs, camelCase, camelCaseOnly, dashes or dashesOnly. Same output as css-loader 7. |
pathAlias |
{} |
Alias overrides checked before tsconfig, e.g. { "@styles": "${workspaceFolder}/src/styles" }. Supports ${workspaceFolder} and ${packageRoot}. |
globalFiles |
[] |
Globs for global stylesheets. Their @imports are followed. |
varShadow.maxDepth |
0 |
How deeply nested a redeclared global variable can be and still get flagged. 0 means top-level rules only, -1 means any depth. |
nodeModules.enabled |
false |
Follow @imports and globalFiles globs into node_modules. Resolving a single composes … from "pkg/x.module.css" works without it. |
diagnostics |
see below | Severity per rule: off, hint, info, warning or error. |
"cssModulesDevTools.diagnostics": {
"missingClass": "error",
"missingFile": "error",
"varShadowsGlobal": "warning",
"globalClassCollision": "warning",
"localShadowsGlobal": "off" // a local .btn when globals.css also has .btn
}
Settings read from other extensions
If you're switching from another extension, a few of its settings carry over while ours are unset.
| Their setting | Used as |
|---|---|
cssModules.pathAlias (clinyong/vscode-css-modules) |
pathAlias |
cssVariables.lookupFiles (vscode-css-variables), only when you set it yourself |
globalFiles |
typescript.preferences.importModuleSpecifier (built in) |
auto-import path style |
Running this extension next to either of those two shows duplicate suggestions, so you get a one-time prompt to disable them.
Works well with
- Biome's
noUndeclaredCustomPropertiesreportsvar(--x)with no declaration. This extension deliberately doesn't, so the two never disagree. Biome follows the import graph and has no option for global files, so a variable that only reaches a module through your layout'sglobals.cssmay be flagged. Turn the rule off for those files withoverridesif that happens. - css-modules-kit on TypeScript 5 or 6 gives TypeScript real types for your modules, which means rename, find references and
tscerrors for missing classes. When its plugin is active, this extension leaves the TS/JS side to it and keeps hover, variables, colors and the CSS-side checks. On TypeScript 7 css-modules-kit's plugin can't load, and this extension handles both sides.
Known limitations
- Duplicate entry in go to definition. Next.js and Vite ship a
declare module '*.module.css', and TypeScript returns it next to the real CSS rule. Extensions can't hide each other's results, so F12 shows a short list. - No rename or find references from TS/JS files. TypeScript owns those requests. TS 7 content mappers will make this possible, and it's on the roadmap.
- Plain CSS only. No SCSS, Less, Stylus, Vue, Svelte or Astro yet. Open an issue if you need one.
- The auto-import check is textual. It skips
styleswhen the name is declared anywhere in the file, not per scope. - TypeScript can grab an unimported
styles.While you typestyles, TypeScript suggests the DOM globalStyleSheet, and the.accepts that suggestion. Press Escape before the dot, or set"editor.acceptSuggestionOnCommitCharacter": false. - Windows is untested. Resolved paths are normalized to native separators, but CI only runs on Linux. Please report path issues.
- Root-absolute paths follow Vite.
/x.cssis checked as a real file path first, then under the package root and the workspace folder. A bundler that serves/from another folder, such aspublic/, isn't followed. :globalcollisions are checked against your global files and against modules already opened in this session. There's no workspace scan, so a clash with a module you haven't opened stays hidden until you open it.
How it compares
| Feature | This extension | css-modules-kit | typescript-plugin-css-modules | vscode-css-modules | vscode-css-variables |
|---|---|---|---|---|---|
| Works on TypeScript 7 | Yes | Not yet | No | Yes | Yes |
| Class completion | Yes | Yes | Yes | Yes | No |
| Go to definition | Yes | Yes | Experimental | Yes | No |
Hover with rules and composes |
Yes | Definition peek | Types only | No | No |
| Missing class errors | Yes | Yes, through tsc | Yes, in the editor | No | No |
| Rename and find references | No | Yes | No | No | No |
Native CSS nesting (&) |
Yes | No | n/a | ||
| tsconfig aliases in monorepos | Yes | Yes | Partial | Needs baseUrl |
n/a |
| camelCase conventions | Yes | No | Yes | Yes | n/a |
var() completion |
Yes, scoped | No | No | No | Yes, workspace-wide |
| Color swatches | Yes | No | No | No | Yes |
| SCSS and Less | No | No | Yes | Yes | Yes |
Empty cells are ones I couldn't confirm from the project's docs or issues.
Thanks
Most of these features already existed, spread across a handful of popular extensions. This one brings them together under a single roof, and it owes a lot to the people who built them first.
- Class completion and go to definition follow clinyong/vscode-css-modules, along with the
pathAliassetting andrequire()support. - Diagnostics through type information, the "add missing rule" quick fix and sibling-first auto-import come from css-modules-kit.
- Hover previews of rule contents, missing module diagnostics and nearest-module auto-import were done first by React CSS modules, which is no longer maintained.
var()completion,lookupFilesand color swatches come from vscode-css-variables.- Typed class names with editor errors come from typescript-plugin-css-modules.
- Inlining
composesdeclarations into the hover,composescompletion, the global namespace checks, per-packageglobalFilesand working the same on every TypeScript version are new here.
The extension icon is built with Lucide icons, licensed under ISC.
License
MIT









