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

preact-css-extract

v0.0.16

Published

Compile-time CSS extraction and Preact classList helper for clean component styling

Readme

preact-css-extract

NPM Version

This package provides the following two main features: a vite plugin for compile-time css extraction and a custom preact classList prop integration based on clsx.

This is inspired by EmotionCSS (that is a bit outdated to my understanding and it doesn't support ViteJS and Preact together) and VueJS class attributes. Also I don't want to use heavy css-in-js solutions or TailwindCSS (for various reasons).

Overview

This project provides tools for managing component styling at build time while maintaining a clean, developer-friendly API. It includes:

  1. CSS Extract Plugin: A Vite plugin that processes template literal CSS declarations and extracts them into a central stylesheet during compilation.

  2. Preact classList Helper: A Preact "option hook" integration that extends the component props API with a classList attribute that forwards class names to the clsx library for conditional class composition.

Usage Example

CSS Extraction with Template Literals

Define styles using the css template literal in your component files:

export function Alert() {
    return (
        <div
            class={css`
                padding: 12px;
                background-color: orangered;
                color: white;
                border-radius: 4px;

                &:hover {
                    background-color: red;
                }
            `}
        >
            Warning!
        </div>
    )
}

As strings are just replaced with their generated class names, you can also define styles in variables for reuse:

import { css } from "preact-css-extract/comptime"

const buttonStyles = css`
    padding: 8px 16px;
    background-color: royalblue;
    color: white;
    border: none;
    border-radius: 4px;

    &:hover {
        background-color: darkblue;
    }
`

export function Button() {
    return <button class={buttonStyles}>Click me</button>
}

The plugin processes these CSS declarations at build time, generates a unique class name based on the content hash (like css-1a2b3c), and injects all styles where the @extracted-css directive is placed in your css files.

Example usage in a css file:

@layer base, components, utilities;

@layer base {
    body {
        margin: 0;
        font-family: system-ui, sans-serif;
        background-color: #f0f0f0;
    }
}

@layer components {
    @extracted-css;
}

@layer utilities {
    .font-bold {
        font-weight: bold;
    }
}

Which results in a final CSS output similar to:

@layer base, components, utilities;

@layer base {
    body {
        margin: 0;
        font-family: system-ui, sans-serif;
        background-color: #f0f0f0;
    }
}

@layer components {
    .css-1a2b3c {
        padding: 8px 16px;
        background-color: royalblue;
        color: white;
        border: none;
        border-radius: 4px;

        &:hover {
            background-color: darkblue;
        }
    }
}

@layer utilities {
    .font-bold {
        font-weight: bold;
    }
}

ClassList Attribute

To enable the Preact clsx integration with the classList attribute, set it up as follows. In your application entry point, add:

import { setupPreactClasslist } from "preact-css-extract"

setupPreactClasslist()

And add a types.d.ts file to your project with the following content to extend the Preact JSX types:

/// <reference path="../node_modules/preact-css-extract/preact-classlist.d.ts" />

Then use the classList prop with object notation, here is an example:

...
<span
    classList={[
        css`
            margin: 0 2rem;
            font-size: 2rem;
        `,
        counter % 2 === 0 && "font-bold",
    ]}
>
    {counter}
</span>
...

This automatically merges with any existing class prop using clsx for proper class concatenation.

Installation

Install the package using npm, yarn, pnpm, or bun:

npm install preact-css-extract
# or
yarn add preact-css-extract
pnpm add preact-css-extract
bun add preact-css-extract

Plugin Setup

To set up the CSS Extract Plugin in your Vite configuration, add the following to your vite.config.ts or vite.config.js:

import { defineConfig } from "vite"

import { cssExtractPlugin } from "preact-css-extract/plugin"
import preact from "@preact/preset-vite"

export default defineConfig({
    plugins: [cssExtractPlugin(), preact()],
})

The plugin accepts an optional configuration object with the following properties:

  • pattern: string | string[] - A glob pattern or array of patterns to specify which files to process. Defaults to "**/*.{ts,tsx,js,jsx}".

  • debug: boolean - Enables debug logging if set to true. Defaults to false.

Caveats

For my needs this is already completely on par with the TailwindCSS "experience" of writing styles near your components, however there are some caveats to be aware of:

  • For now I've kept the generated css very simple, there is no added scoping or style collision prevention. This means that if you have two components that generate the same css, they will share the same class name. This is not necessarily a bad thing, but something to be aware of.

  • The CSS extraction is currently based on a simple regular expression. This means that the css strings must be known at compile time and cannot be dynamically generated.

    I think this is a reasonable compromise as one can use specialized utility classes as in the example above to dynamically add styles, or just update styles directly with the style attribute.

  • CSS snippets are hashed to 6-character class names, I hope its enough to avoid collisions. Fire me an issue if you find any and we'll have a laugh at the examples together...

Improvements and Future Work

  • Set explicitly the class name of a css snippet, something like:

    const buttonStyles = css("my-button")`
        background-color: blue;
        color: white;
        ...
    `

    or just extract the first class present in the css snippet:

    const buttonStyles = css`
        .my-button {
            background-color: blue;
            color: white;
            ...
        }
    `
  • Better handling for scoped styles

  • More robust CSS parsing instead of regex-based extraction

License

This project is licensed under the MIT License. See the LICENSE file for details.