Find and remove unused CSS classes across a project.
./build.shRequires Odin in PATH.
uncss [all] [flags]
Report mode (default) — prints unused classes, no files modified:
uncss
uncss --json
Apply mode — rewrites CSS files, backups written as .bak:
uncss all
uncss all --no-backup --yes
| Flag | Default | Description |
|---|---|---|
--ext=<list> |
.css,.less,.scss,.sass |
CSS file extensions |
--markup-ext=<list> |
.html,.htm,.jsx,.tsx,.vue,.svelte,.astro,.php,.erb,.hbs,.mustache,.twig,.ejs |
Markup file extensions |
--ignore=<list> |
node_modules,dist,build,.git,.next,vendor,target |
Directory names to skip |
--no-backup |
— | Skip .bak backup in apply mode |
--json |
— | Machine-readable JSON output |
--yes, -y |
— | Skip confirmation prompt |
-h, --help |
— | Show help |
path/to/file.css:12:1 .unused-class
path/to/other.css:34:5 .another-class
3 unused class(es) across 2 file(s)
- Walk project from CWD, collect
.css/.less/.scss/.sassand markup files. - Scan markup for
class=/className=attribute values — build a "used classes" set. - Parse CSS: tokenize selector lists, extract
.classnametokens with positions. - Diff: classes in CSS not found in markup = unused.
- Report or remove.
- Files containing
@tailwindor@applyare skipped (Tailwind generates classes dynamically). - Rules containing
&,#{,@include,@mixin,@extendare skipped (SCSS/LESS risk). - Only pure class selectors (e.g.
.foo,.foo .bar,.foo:hover) are removed; selectors with tag names, IDs, or attribute selectors are kept. - Apply mode writes
.bakbackups by default.
- Dynamic classes (
`btn-${variant}`) → false positives (class appears unused but isn't). - SCSS/LESS variables and mixins not resolved.
- CSS Modules hash names not supported.
- CSS-in-JS (styled-components, emotion) not scanned.