npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

styleleak

v0.1.1

Published

Find and eliminate unused CSS classes in your TypeScript/React project

Readme

styleleak

Find and eliminate unused CSS classes in your TypeScript / React project.

npm version license


The Problem

Over time, as components get deleted and features get removed, stylesheets accumulate orphaned classes that nobody uses but nobody dares delete.

/* card.module.css */
.card         { ... }   /* ✅ used in Card.tsx */
.cardV2       { ... }   /* ❌ refactored 4 months ago */
.wrapperOld   { ... }   /* ❌ component was deleted */
.promoBadge   { ... }   /* ❌ feature was removed */

styleleak tells you instantly what's safe to delete.


Installation

# Run without installing
npx styleleak ./src

# Install globally
npm install -g styleleak

# Install as a dev dependency
npm install -D styleleak

Quick Start

# Scan your src folder
styleleak ./src

# See file sizes and potential savings
styleleak ./src --size

# Preview what would be removed (safe, no file changes)
styleleak ./src --dry-run

# Remove all unused classes
styleleak ./src --fix

Sample Output

styleleak — scanned 42 CSS files, 118 component files

  src/styles/card.module.css                    [4.2 KB → 3.8 KB]
    ✗ .cardV2           (120 bytes)
    ✗ .wrapperOld       (98 bytes)

  src/styles/global.css                         [12.8 KB → 12.2 KB]
    ✗ .old-sidebar-item (380 bytes)
    ✗ .promo-badge      (210 bytes)

  src/components/Nav/Nav.module.css             [2.1 KB → 2.0 KB]
    ✗ .navItemActive    (64 bytes)

────────────────────────────────────────────────────
  5 unused classes across 3 files
  Potential savings: ~872 bytes
  Run with --dry-run to preview, --fix to remove
────────────────────────────────────────────────────

All Options

Scanning & Scope

[dir] — Directory to scan

Pass a directory as the first argument. Defaults to the current directory.

styleleak ./src
styleleak ./app
styleleak .

--dir — Scan specific folders

Scan one or more specific folders. Can be repeated.

styleleak --dir ./src/components --dir ./src/pages

--css-ext — CSS file types to scan

Comma-separated list of CSS extensions. Default: css,scss,module.css

# Only SCSS files
styleleak ./src --css-ext scss

# CSS and SCSS only (skip modules)
styleleak ./src --css-ext css,scss

# Include Less files
styleleak ./src --css-ext css,scss,less

--js-ext — Component file types to scan

Comma-separated list of JS/TS extensions. Default: tsx,jsx,ts,js

# Only TSX and JSX
styleleak ./src --js-ext tsx,jsx

# Include Vue SFCs
styleleak ./src --js-ext tsx,jsx,vue

--exclude — Exclude files or folders

Glob patterns to exclude. Can be repeated.

styleleak ./src --exclude "**/legacy/**"
styleleak ./src --exclude "**/legacy/**" --exclude "**/*.test.css"

--only-modules — Only scan CSS Modules

Limits CSS scanning to .module.css and .module.scss files only.

styleleak ./src --only-modules

--only-global — Only scan global stylesheets

Skips CSS Modules and only scans plain .css / .scss files.

styleleak ./src --only-global

--git-staged — Only scan staged files

Scans only files currently staged in git. Ideal for pre-commit hooks.

styleleak --git-staged
// package.json — use with lint-staged
"lint-staged": {
  "*.{css,scss}": ["styleleak --git-staged --threshold 0"]
}

Output & Reporting

--size — Show file sizes and savings

Displays current file size, estimated size after cleanup, and bytes saved per class.

styleleak ./src --size
  src/styles/card.module.css     [4.2 KB → 3.8 KB]
    ✗ .cardV2       (120 bytes)
    ✗ .wrapperOld   (98 bytes)

  Potential savings: 218 bytes

--format — Output format

Choose between table (default), json, or text.

# Default colored table
styleleak ./src --format table

# Machine-readable JSON (great for CI)
styleleak ./src --format json

# Plain text (great for log files)
styleleak ./src --format text
# Save JSON report
styleleak ./src --format json --output styleleak-report.json

--sort — Sort results

Sort unused classes by file (default), size (biggest savings first), or name (alphabetical).

# Biggest savings first
styleleak ./src --sort size

# Alphabetical by class name
styleleak ./src --sort name

# Grouped by file path (default)
styleleak ./src --sort file

--summary-only — Print totals only

Prints a single summary line instead of the full per-class breakdown.

styleleak ./src --summary-only
# → 5 unused classes across 3 files (872 bytes)

--output — Save report to a file

styleleak ./src --output report.txt
styleleak ./src --format json --output report.json

--report-possibly-used — Show dynamic class warnings

Lists classes used in dynamic expressions (btn-${variant}, clsx(...)) with a ⚠ warning.

styleleak ./src --report-possibly-used
  ⚠ .btn-primary   (possibly used — dynamic class, cannot verify)

--verbose — Show scan progress

styleleak ./src --verbose
# Shows: dirs scanned, file counts, timing

--silent — No output, exit code only

Produces no terminal output. Returns exit code 0 if clean, 1 if leaks are found.

styleleak ./src --silent
echo $?  # 0 = clean, 1 = leaks found

Fixing

--dry-run — Preview removals

Shows exactly what --fix would delete, without touching any files. Always run this first.

styleleak ./src --dry-run
  [dry-run] Would remove .cardV2 from src/styles/card.module.css
  [dry-run] Would remove .wrapperOld from src/styles/card.module.css
  [dry-run] 2 classes would be removed from src/styles/card.module.css

--fix — Auto-remove unused classes

Removes all unused class blocks from your CSS files directly.

styleleak ./src --fix

Always run --dry-run first to review what will be removed.


--backup — Back up files before fixing

Creates a .bak copy of each file before --fix modifies it.

styleleak ./src --fix --backup
# Creates: card.module.css.bak, global.css.bak, etc.

--interactive — Confirm each removal

Steps through each unused class one by one and asks you to confirm before removing — like git add -p for CSS cleanup.

styleleak ./src --interactive
  ? Remove .cardV2 from card.module.css? (120 bytes) [y/n]
  ? Remove .wrapperOld from card.module.css? (98 bytes) [y/n]

Safety & CI

--threshold — Fail above N unused classes

Returns exit code 1 when unused classes exceed the threshold. Use in CI to block merges.

# Fail on any unused class
styleleak ./src --threshold 0

# Allow up to 5 unused classes before failing
styleleak ./src --threshold 5
# .github/workflows/styleleak.yml
- name: Check for unused CSS
  run: npx styleleak ./src --threshold 0 --silent

--min-age — Skip recently modified files

Uses git blame to skip CSS files modified within the last N days. Prevents flagging newly added classes that haven't been wired up yet.

# Skip files modified in the last 7 days
styleleak ./src --min-age 7

--ignore — Ignore specific class names

Treat specific class names as used, even if they don't appear in source files. Useful for classes added at runtime via JavaScript.

styleleak ./src --ignore tooltipVisible --ignore js-modal-open

--ignore-file — Skip specific CSS files

styleleak ./src --ignore-file src/styles/animations.css

--allowlist — Point to an allowlist file

Load a file of class names to always treat as used.

styleleak ./src --allowlist .styleleak-allowlist
# .styleleak-allowlist
# One class per line. Lines starting with # are comments.
tooltipVisible
js-modal-open
is-active
fade-enter-active

If no --allowlist flag is passed, styleleak automatically reads .styleleak-allowlist from the current directory if it exists.


Configuration File

--config — Load options from a config file

Define all your options once in a config file instead of passing flags every time.

styleleak --config styleleak.config.js
// styleleak.config.js
module.exports = {
  dirs: ['./src/components', './src/pages'],
  cssExt: ['css', 'scss'],
  jsExt: ['tsx', 'jsx'],
  exclude: ['**/legacy/**'],
  size: true,
  sort: 'size',
  threshold: 0,
  allowlist: '.styleleak-allowlist',
}

If no --config flag is passed, styleleak automatically looks for styleleak.config.js or .styleleakrc.js in the current directory.


Safe Workflow (Recommended)

# 1. Audit — see what's unused and how big
styleleak ./src --size --sort size

# 2. Preview — see exactly what --fix will delete
styleleak ./src --dry-run

# 3. Remove with backup — just in case
styleleak ./src --fix --backup

# 4. Verify — make sure everything still compiles
npm run build

CI Integration

# Fail the build if any unused classes are found
styleleak ./src --threshold 0 --silent
# .github/workflows/ci.yml
jobs:
  styleleak:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
      - run: npx styleleak ./src --threshold 0 --format json --output styleleak.json
      - uses: actions/upload-artifact@v4
        if: failure()
        with:
          name: styleleak-report
          path: styleleak.json

Pre-commit Hook (lint-staged)

npm install -D lint-staged husky
// package.json
"lint-staged": {
  "*.{css,scss}": ["styleleak --git-staged --threshold 0"]
}

Known Limitations

| Scenario | Behavior | |---|---| | className={`btn-${variant}`} | Cannot be statically detected — use --ignore or --allowlist | | clsx('foo', isActive && 'bar') | Static string args detected; dynamic expressions skipped | | Classes added via JS at runtime | Not detectable — add to .styleleak-allowlist | | Tailwind utility classes | Not designed for Tailwind — works best with custom CSS / SCSS / CSS Modules |


Programmatic API

Use styleleak as a library in your own tools:

import { scan, defaultConfig } from 'styleleak'

const report = await scan({
  ...defaultConfig,
  dirs: ['./src'],
  size: true,
})

console.log(`Found ${report.totalUnused} unused classes`)
console.log(`Potential savings: ${report.totalSavingsBytes} bytes`)

for (const file of report.files) {
  console.log(file.filePath, file.unusedClasses.map(c => c.name))
}

License

MIT