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

inline-css-modules

v0.3.0

Published

Zero-runtime CSS Modules written inline in your JS/TS files via a css template literal, scoped and extracted at build time by Vite or esbuild.

Readme

Inline CSS Modules

If you use CSS Modules, why are we putting our CSS in another file? VS Code — and most other editors — will syntax-highlight CSS in a JavaScript template literal just fine.

This is the way (_btw don't):

import { css } from 'inline-css-modules'

const styles = css`
  .page {
    display: flex;
    gap: 1rem;
  }
  .title {
    font-weight: 700;
  }
`

export const Header = () => (
  <div className={styles.page}>
    <h1 className={styles.title}>Inline CSS Modules</h1>
  </div>
)

Your bundler rewrites every css`...` block at build time: class selectors are scoped (.page.page_a1b2), the literal becomes a plain object ({ page: "page_a1b2" }), and the scoped CSS is extracted into a real stylesheet that flows through your usual CSS pipeline. Nothing ships to runtime — the css tag exists only for types and editor highlighting.

Why

  • Colocation. Styles live next to the markup that uses them, in the same file.
  • Zero runtime. No CSS-in-JS engine, no injected <style> tags. The output is identical in spirit to CSS Modules — a static class map plus an extracted .css file.
  • Type-safe. Get autocomplete and checked class names with a generic.
  • Real CSS Modules. Local scoping by default, with :global / :local and composes escape hatches.
  • No dependencies. Native string handling, nothing to audit.

Install

npm install -D inline-css-modules

Setup

Add the plugin for your bundler.

Vite

import { defineConfig } from 'vite'
import { inlineCssModules } from 'inline-css-modules/vite'

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

Scoped CSS routes through Vite's own pipeline, so PostCSS, HMR in dev, and extraction/minification in build all work as they do for an imported stylesheet.

esbuild

import * as esbuild from 'esbuild'
import { inlineCssModules } from 'inline-css-modules/esbuild'

await esbuild.build({
  entryPoints: ['src/main.tsx'],
  bundle: true, // required — emits the .css output, same as CSS Modules
  outdir: 'dist',
  plugins: [inlineCssModules()],
})

Usage

Typed class names

Pass the local names as a generic for autocomplete and type checking:

const styles = css<{ page: string; title: string }>`
  .page { display: flex; }
  .title { font-weight: 700; }
`

styles.page    // ✓ string
styles.unknown // ✗ type error

:global and :local

Opt class names out of (or back into) scoping — function, switch, and block forms are all supported:

css`
  :global(.no-scope) { color: red; }

  .card :global .legacy-child { color: blue; }

  :global {
    body { margin: 0; }
  }
`

composes

Compose local classes from the same block; the result is folded into the exported map:

css`
  .base   { padding: 1rem; }
  .button { composes: base; background: black; }
`
// styles.button === "base_a1b2 button_c3d4"

composes: ... from "file" is not supported — an inline block has no external file to compose from.

Custom scoped names

inlineCssModules({
  generateScopedName: ({ local, filename, hash }) =>
    `${local}__${hash}`,
})

Notes

  • Static CSS only. A ${} interpolation inside a css`...` block is a build error — move dynamic values to CSS custom properties set at runtime.
  • Editor highlighting. The styled-components / lit-html VS Code extensions highlight CSS in a css tag automatically; no extra config needed.
  • Testing. Run your test files through the same transform (or the inline-css-modules/transform core) so css`...` blocks are replaced before they reach the runtime.

License

MIT