Docs
Search

CSS Purge

CSS Purge scans your build output and keeps only the Lism CSS classes you actually use. Plugins for Vite and Astro are available from the @lism-css/plugin package.

CSS Purge can only detect complete class names that appear as literal strings in the generated HTML / JS. Classes generated from props on the client, such as in SPAs or Astro client:only islands, cannot be detected automatically, even with static prop values. Read Scope and limitations before enabling it.

pnpm add -D @lism-css/plugin

If you are using the @lism-css/plugin integrated plugin, just pass purge: true to enable it.

astro.config.mjs
import { defineConfig } from 'astro/config';
import { lismCss } from '@lism-css/plugin/astro';
export default defineConfig({
integrations: [lismCss({ purge: true })],
});
vite.config.js
import { defineConfig } from 'vite';
import { lismCss } from '@lism-css/plugin/vite';
export default defineConfig({
plugins: [lismCss({ purge: true })],
});

You can also pass an object to configure individual CSS Purge options:

lismCss({
purge: {
report: true, // Log the file size before/after CSS Purge to the build log
safelist: ['-p:30'], // Keep classes not detected by static analysis
},
});

You can also use the standalone plugins directly: lismPurge from @lism-css/plugin/purge/vite and lismPurgeAstro from @lism-css/plugin/purge/astro.

How it works

At build time, the plugin scans the generated HTML / JS for class names that follow Lism CSS conventions (the c-- / a-- / l-- / is-- / has-- / set-- / u-- prefixes, plus -prop:value style Property Classes). It then parses the CSS files and keeps only the rules whose selectors reference the collected classes.

  • Only targets CSS that contains selectors matching the Lism naming conventions above (CSS without any matching selector passes through unchanged)
  • Does not change your own classes or styles from other libraries
  • Classes inside :not() / :has() are not counted as used classes
  • Attribute selectors such as [class*="-p:"] that match used classes or the safelist are kept

Scope and limitations

React / Astro components convert props into class names at runtime. For example, <Box p="20"> produces -p:20, but the client JS may only contain p: "20". Even a static prop value does not protect its CSS from removal if the complete class name is absent from the build output.

Setup or case What can be detected
Astro SSG (prerender) Classes rendered in the final HTML
SPAs (such as Vite + React) Classes generated from props in CSR regions cannot be detected automatically
Astro client:only Classes generated from props cannot be detected automatically because the initial HTML has no rendered component output
Prop values that change after hydration Classes absent from both the initial HTML and literal strings in JS cannot be detected
On-demand SSR pages Only complete class names in server chunks; classes assembled from props at request time cannot be detected
Next.js No CSS Purge plugin is provided (the integrated plugin only supports CSS building)

For example, if <Box p={isOpen ? 20 : 40}> only renders the 20 branch into HTML at build time, -p:40 for the other branch is not retained unless that complete string appears elsewhere in the build output. Keep all classes needed by these regions using safelist. If listing the classes or matching their families is impractical, disable purge by omitting the integrated plugin’s purge option, setting it to false, or removing the standalone purge plugin.

Build warnings are emitted under these conditions:

  • Astro: output HTML contains a client:only island.
  • Vite: client JS chunks include the Lism runtime and no Lism classes are detected in HTML.

Warnings are emitted even when safelist is configured, because its presence does not prove that all required classes are protected. These checks do not detect every missing class: the absence of a warning does not guarantee that classes generated from props are retained.

Using the standalone plugin directly

You can also add the standalone plugin to your Vite or Astro config without the integrated plugin.

import { defineConfig } from 'vite';
import { lismPurge } from '@lism-css/plugin/purge/vite';
export default defineConfig({
plugins: [lismPurge()],
});

The Vite plugin runs as apply: 'build' / enforce: 'post', so nothing happens during vite dev. Unused selectors are stripped only when you run vite build. The Astro integration hooks into astro:build:done, scans HTML / JS under the build output, and rewrites the CSS files in place.

In SSR / hybrid setups (output: 'server', or when some routes have prerender = false), the server output (dist/server/) is also scanned and reference-rewritten in addition to the client output (dist/client/). Classes used only on on-demand pages are retained if they appear as complete literal strings in server chunks. Classes assembled from props at runtime still require the measures described in Scope and limitations.

Pairing with full.css

lism-css/full.css is a full build that adds breakpoint-aware classes and color-token classes not included in main.css (see CSS File Types for what’s included). It is large when loaded as-is, so it ships as a build meant to be paired with CSS Purge.

// Load full.css instead of main.css
import 'lism-css/full.css';

Once CSS Purge is enabled and you switch to full.css, you gain access to token classes and extended breakpoints that main.css does not include, while the final CSS is narrowed down to only the classes actually used across the whole site.

Loading full.css without CSS Purge ships a large CSS that still contains every unused class. Always pair full.css with CSS Purge.

Options

Both the purge option of the integrated plugin and the standalone plugin accept the same LismPurgeOptions.

Option Description
safelist Keep classes that static analysis cannot detect
report Log the file size before and after CSS Purge
known Override the set of classes CSS Purge treats as “Lism classes” (rarely needed)

safelist

Class names that are assembled dynamically in JS — i.e. names that never appear as a literal string in the build output — cannot be detected by static analysis. Add them to safelist to prevent accidental removal.

lismPurge({
safelist: [
// Exact string match
'-p:30',
// Regex match
/^-bgc:/,
// Custom predicate
(className) => className.startsWith('-fz:'),
],
});

string entries are also used when matching attribute selectors (such as [class*="..."]). RegExp and function entries can’t enumerate concrete class names, so they can’t be matched against attribute selectors — if even one such entry is present, every attribute selector that doesn’t match a used class or a string entry is kept.

report

When true, the total byte count before / after CSS Purge and the reduction ratio are printed to the build log.

CSS: 28100 → 13200 bytes (-14900 / -53.0%)

known

The set of classes CSS Purge treats as “Lism classes.” When not specified, it’s automatically built from the config-reflected full.css at the start of the build, so unused classes derived from props / tokens you added in lism.config.js are correctly removed too. Since full.css includes every selector in main.css, nothing is missed regardless of which one you load. Passing a function calls it at build time and uses the return value as the list.

Caveats

  • When switching class names, write complete literal strings, such as size === 'l' ? '-p:40' : '-p:30'. Neither template literals like `-p:${size}` nor concatenation like '-p:' + size expose a complete class name for detection. If complete strings are impractical, add the classes to safelist.
  • CSS Purge keeps every class used anywhere in the entire build output (not per page). A class is retained as long as it is used on any page, even if it is unused on a given page. This is intentional so that a single CSS shared across multiple pages is never broken.
  • CSS Purge only targets CSS emitted by Lism CSS. Your own CSS and styles from other libraries are not changed.
  • CSS Purge runs independently of the unused-class removal features of other frameworks such as Tailwind CSS.
  • CSS sourcemaps are not supported. CSS Purge removes rules, so an existing sourcemap no longer lines up. To avoid stale mappings, CSS Purge strips sourceMappingURL comments from the processed CSS and removes old .css.map files. Disable CSS Purge if you need CSS sourcemaps.
  • With the Vite plugin, when CSS Purge changes a CSS file name (its content hash), the file names of JS chunks that reference the CSS are not recalculated — chunk names are finalized before the CSS Purge step runs. The chunk contents are rewritten to point to the new CSS name, but since the chunk file name stays the same, a stale chunk cached by a CDN with file-name-based immutable caching may keep referencing an old CSS file name that no longer exists, resulting in a 404. Invalidate the CDN cache on deploy if this applies to your setup.
  • A CSS file targeted by CSS Purge is treated as hash-named and renamed to a content-based hash when the last segment of its file name is exactly 8 alphanumeric characters (<name>.xxxxxxxx.css, and also <name>-xxxxxxxx.css with the Vite plugin). Non-hash names such as app-critical.css also match this pattern, so avoid file names whose last segment is exactly 8 alphanumeric characters if you reference an output CSS file directly by a fixed name from outside the build output.

© 2026 Lism CSS.