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

roxcss

v0.0.1

Published

Runtime atomic CSS engine: template-string tag that parses class names and injects rules on the fly.

Readme

roxcss

roxcss is a runtime atomic CSS engine. It is a template-string tag function that parses class names on the fly and injects the matching CSS rules into the document. No build step, no configuration file, no purge phase — whatever class name you write, the rule is generated when it is first used.

roxcss 是一个运行时原子 CSS 引擎。它是一个模板字符串标签函数,在调用时动态解析类名并注入对应的 CSS 规则。没有构建步骤、没有配置文件、没有清除阶段——你写出什么类名,规则就在首次使用时生成。

Features / 特性

  • Zero build, zero config — rules are generated and injected at runtime, the first time a class name is used. Nothing to precompile.

  • Framework-agnostic — works anywhere a template-string tag works: plain HTML, Vue, React, and more.

  • No hidden class names — the class you write is the class in the DOM and the selector in DevTools. What you see is what you typed.

  • Values, not magicw-170px means exactly width: 170px. No numeric scale sits between the class name and the CSS.

  • Tailwind-style preset — a built-in preset reuses Tailwind v4 utility names, ready to extend or replace (see Default Preset / 默认预设).

  • Synchronous — the rules are live the moment the call returns.

  • 零构建、零配置:类名首次使用时,规则在运行时生成并注入,无需任何预编译。

  • 框架无关:任何模板字符串标签可用的地方都能用——原生 HTML、Vue、React 等。

  • 类名即真相:你写下的类名就是 DOM 中的类、DevTools 中的选择器。所见即所写。

  • 无魔法值w-170px 就是 width: 170px。类名与 CSS 之间没有数值刻度。

  • Tailwind 风格预设:内置预设复用 Tailwind v4 工具类命名,可自由扩展或替换(见 Default Preset / 默认预设)。

  • 天生同步:调用返回的瞬间,规则已经生效。

Quick Start / 快速开始

Install the package, then import the default instance and use it as a template tag. The class names you write are returned unchanged, and the matching rules are injected into <head>:

安装依赖后导入默认实例 rox,并把它作为模板标签使用。你写下的类名会原样返回,匹配的规则注入 <head>

npm install roxcss
import { rox } from "roxcss";

// class names are returned unchanged / 类名原样返回
const className = rox`flex flex-col gap-16px p-24px rounded-8px hover:bg-blue`;

document.body.className = className;
// <body class="flex flex-col gap-16px p-24px rounded-8px hover:bg-blue">

The call injects these rules into a <style data-roxcss> element in <head>:

这次调用向 <head> 中的 <style data-roxcss> 元素注入以下规则:

[class~="flex"] {
  display: flex;
}
[class~="flex-col"] {
  display: flex;
  flex-direction: column;
}
[class~="hover:bg-blue"]:hover {
  background: blue;
}

The tag function is sync: when the call returns, the rules are live. Repeated calls with the same class names hit the cache and never touch the style layer again — steady-state rendering costs nothing beyond the returned string.

标签函数是同步的:调用返回时规则已生效。相同类名的重复调用命中缓存,之后不再触碰样式层——稳定态渲染除了返回字符串外零开销。

rox is the out-of-the-box instance built on the default preset. When you need a preset-free setup — a design system with its own vocabulary, a framework-specific shim, or an experiment — build your own matcher tree with createRox. The minimal instance below registers two spacing utilities and one layout utility, plus an md breakpoint modifier:

rox 是基于默认预设的开箱即用实例。当需要脱离预设——自有词汇的设计系统、框架专用垫片或临时实验——用 createRox 自建 matcher 树。下面的最小实例注册了两个间距工具、一个布局工具,以及 md 断点修饰符:

import { createRox } from "roxcss";

const myRox = createRox({
  matchers: {
    p: (v) => `padding:${v}`,
    m: (v) => `margin:${v}`,
    flex: {
      "": () => "display:flex",
      col: () => "display:flex;flex-direction:column",
    },
  },
  modifiers: {
    md: (selector, cssDecl) => `@media (min-width: 768px) { ${selector} { ${cssDecl} } }`,
  },
});

myRox`md:flex-col p-16px`;
// the media-wrapped rule is injected / 媒体查询包裹的规则被注入

CDN Usage / CDN 用法

No install, no bundler — load the package straight from a CDN in a plain HTML page. Two builds are published; pick one by how you use roxcss:

无需安装、无需打包——在普通 HTML 页面中直接从 CDN 加载。两个构建按使用方式选择:

Full build / 全量构建

The default build bundles the default preset — rox, createConfig, createModifiers, and the breakpoint table — ready to use:

默认构建内置默认预设——roxcreateConfigcreateModifiers 与断点表——开箱即用:

<script type="module">
  import { rox } from "https://unpkg.com/roxcss/index.min";

  // class names are returned unchanged, rules are injected / 类名原样返回并注入规则
  document.body.className = rox`flex flex-col gap-16px p-24px hover:bg-blue`;
</script>

Core build / 核心构建

The core build ships only the engine — createRox plus the DOM injection — at about 2 kB minified. Use it when you bring your own matchers and skip the preset:

核心构建只含引擎——createRox 与 DOM 注入——压缩后约 2 kB。自带 matcher、不需要预设时使用:

<script type="module">
  import { createRox } from "https://unpkg.com/roxcss/core.min";

  // build your own matchers, no default preset / 自建 matcher,无默认预设
  const rox = createRox({
    matchers: {
      p: (v) => `padding:${v}`,
      bg: (v) => `background:${v}`,
    },
  });
  document.body.className = rox`p-24px bg-blue`;
</script>

Both URLs serve the latest published version from unpkg; pin an exact version in production, e.g. https://unpkg.com/[email protected]/index.min.

两个 URL 均由 unpkg 提供最新发布版本;生产环境建议固定版本,如 https://unpkg.com/[email protected]/index.min

How It Works / 工作方式

A token is split by - into segments, and the segments walk a nested matcher tree with two kinds of nodes — functions and objects:

token 按 - 拆成段,段在嵌套的 matcher 树中逐段查找。节点只有两种——函数与对象:

Function node / 函数节点

A function swallows the remaining segments and is called with one argument per segment. It returns the declaration text — or null to mark failure.

函数吞掉剩余所有段,剩余段每段一个参数调用,返回声明文本——返回 null 表示失败。

// matcher definition (a function node) / matcher 定义(函数节点)
p: (v) => `padding:${v}`;

// token flow / token 解析流程
//   p-24px
//     → segments ["p", "24px"]
//     → "p" is a function, swallows the rest → p("24px")
//     → padding:24px

Object node / 对象节点

An object is a container that remaining segments descend through as keys. The "" key is the fallback — used when the segments run out or no key matches.

对象是容器,剩余段作为键逐层下行。"" 键是兜底——段耗尽或无键匹配时使用。

// matcher definition (an object node) / matcher 定义(对象节点)
flex: {
  "": () => "display:flex",
  col: () => "display:flex;flex-direction:column",
}

// token flow / token 解析流程
//   flex-col
//     → segments ["flex", "col"]
//     → "flex" is an object, descend by key "col" → flex.col()
//     → display:flex;flex-direction:column
//   flex
//     → segments ["flex"], segments run out, object has "" → flex[""]()
//     → display:flex

Match resolution, in order: exact key → "" fallback → failure. On failure the token is returned unchanged and no rule is injected. A function returning null also means failure.

匹配解析顺序:精确键 → "" 兜底 → 失败。失败时 token 原样返回且不注入规则。函数返回 null 同样视为失败。

Prefixes: pseudo-classes and environment modifiers / 前缀:伪类与环境修饰符

Tokens split by : — the first parts are prefixes, the last part is the matcher key. Each prefix part is checked against the modifiers registry: registered ones are environment modifiers (at most one — they wrap the whole rule in @media, .dark, etc.), the rest are treated as pseudo-classes and appended to the selector freely in any order and amount.

token 按 : 拆分——前面的部分是前缀,最后一段是 matcher 键。每个前缀段先查 modifiers 注册表:命中的是环境修饰符(最多一个——它把整条规则包裹进 @media.dark 等环境),其余一律视为伪类,任意数量、任意顺序拼接到选择器上。

// → [class~="hover:p-8px"]:hover { padding:8px }
myRox`hover:p-8px`;

// → @media (min-width:768px) { [class~="md:flex-col"] { display:flex;flex-direction:column } }
myRox`md:flex-col`;

// → @media (min-width:768px) { [class~="md:hover:focus:p-8px"]:hover:focus { padding:8px } }
myRox`md:hover:focus:p-8px`;

Cache / 缓存

Each token is resolved exactly once per instance. Injected and failed tokens are remembered in two Sets — a repeated render costs a single cache lookup and nothing else.

每个 token 在每个实例中只解析一次。已注入与已失败的 token 分别记入两个 Set——重复渲染只付出一次缓存查询,再无其他。

API / API 参考

createRox(options)

createRox creates a fully independent instance with its own matcher tree, injection caches (injected / failed), and rule memory. Multiple instances can coexist without sharing any state. Pair it with createConfig for a preset-based instance, or pass a hand-written tree for a preset-free one:

createRox 创建完全独立的实例——各自的 matcher 树、注入缓存(injected / failed)与规则内存。多个实例可并存,互不共享状态。配合 createConfig 得到基于预设的实例;传入手写 matcher 树则脱离预设:

  • matchers Record<string, MatcherNode>

  • modifiers Record<string, Modifier> (optional / 可选)

    • environment modifier registry, keyed by prefix name. Defaults to an empty registry, in which case every prefix is treated as a pseudo-class.
    • 环境修饰符注册表,以前缀名为键。默认空注册表,此时所有前缀都按伪类处理。

RoxInstance

The object returned by createRox — a callable template tag carrying a getCSS method.

createRox 的返回值——可调用的模板标签函数,挂载 getCSS 方法。

interface RoxInstance {
  (strings: TemplateStringsArray, ...values: unknown[]): string;
  getCSS(): string;
}
  • (strings, ...values)

    • tag invocation: splits the interpolated string on whitespace, resolves each token, and joins the results with a space — the class-name string you can put on an element. Rules are flushed synchronously when the call returns.
    • 标签调用:按空白拆分插值后的字符串,逐个解析 token,用空格连接结果——即可直接放到元素上的类名字符串。调用返回时规则同步写入。
  • getCSS()

    • returns every rule the instance has injected so far, joined with newlines. Useful for SSR style collection and debugging; works even without a DOM.
    • 返回实例迄今注入的全部规则,换行连接。适用于 SSR 样式收集与调试,无 DOM 时同样可用。

rox

The default instance: createRox(createConfig()) — the out-of-the-box matcher tree plus sm2xl breakpoint modifiers. Use it directly when the default preset fits; build a custom instance with the factories below when it does not.

默认实例:createRox(createConfig())——开箱即用的 matcher 树加 sm2xl 断点修饰符。默认预设适用时直接使用;不适用时用下面的工厂函数构建自定义实例。

createConfig(overrides?)

Creates the default preset — a fresh matcher tree (90+ top-level roots) plus fresh breakpoint modifiers. Every call rebuilds the whole tree, so instances sharing a config never share references.

创建默认预设——全新的 matcher 树(90+ 顶层根)与全新的断点 modifiers。每次调用整树重建,共享同一 config 的实例之间零引用共享。

createModifiers(breakpoints?)

Creates breakpoint environment modifiers from a name → pixel table. The passed table completely determines the output — no implicit merging with the default.

根据"名称 → 像素"表创建断点环境修饰符。传入的表完全决定输出——不会隐式合并默认断点。

createModifiers({ ...defaultBreakpoints, xxl: 1700 });
// each breakpoint name produces a min-width media query / 每个断点名生成一条 min-width 媒体查询

defaultBreakpoints

| Breakpoint / 断点 | Min-width / 最小宽度 | | ----------------- | -------------------- | | sm | 640px | | md | 768px | | lg | 1024px | | xl | 1280px | | 2xl | 1536px |

Types / 类型

Every type is exported from roxcss alongside the functions. The structural types are spelled out in the entries above; the core shapes are:

全部类型与函数一同从 roxcss 导出。结构性类型的完整定义见上方 API 条目,核心形状如下:

  • MatcherFunction (...args: string[]) => string | null

    • leaf of the matcher tree; one argument per remaining segment. Returning null marks failure.
    • matcher 树叶子;剩余段每段一个参数。返回 null 表示匹配失败。
  • MatcherNode MatcherFunction | { [key: string]: MatcherNode }

    • a leaf function, or a nested container whose keys are segment names and whose "" key is the fallback.
    • 叶子函数,或嵌套容器——键是段名,"" 键为兜底。
  • Modifier (selector: string, cssDecl: string) => string

    • wraps a complete rule in an environment (@media, .dark, …) given the final selector and declaration.
    • 根据最终选择器与声明,把完整规则包裹进环境(@media.dark 等)。
  • MatcherPatch MatcherFunction | null | { [key: string]: MatcherPatch }

    • the override shape for createConfig: same as MatcherNode, plus null to delete a key.
    • createConfig 的覆盖形状:与 MatcherNode 相同,多出的 null 表示删除键。
  • RoxOptions { matchers: Record<string, MatcherNode>; modifiers?: Record<string, Modifier> }

    • the input of createRox.
    • createRox 的入参。
  • Preset { matchers: Record<string, MatcherNode>; modifiers?: Record<string, Modifier> }

    • the output of createConfig.
    • createConfig 的返回。
  • PresetOverrides { matchers?: Record<string, MatcherPatch>; modifiers?: Record<string, Modifier | null> }

    • the input of createConfig.
    • createConfig 的覆盖入参。
  • RoxInstance — see the RoxInstance entry above: a callable template tag with getCSS.

    • 见上方 RoxInstance 条目:可调用模板标签 + getCSS

Customization / 自定义

Writing matchers / 编写 matcher

Recall the matcher shape from How It Works / 工作方式: each remaining segment arrives as one argument, and the function returns the declaration string. In practice, single-segment values read the argument directly, while multi-segment values spread:

回顾 How It Works / 工作方式 中的 matcher 形态:剩余段每段一个参数,函数返回声明字符串。实际写法上,单段值直接读取参数,多段值用 rest 展开:

createRox({
  matchers: {
    // one segment / 单段:text-14px → font-size:14px
    text: (v) => `font-size:${v}`,
    // multiple segments joined with spaces / 多段空格连接:rounded-4px-8px → border-radius:4px 8px
    rounded: (...vs) => `border-radius:${vs.join(" ")}`,
  },
});

A function returning null marks the token as failed (warning in dev, nothing injected).

函数返回 null 表示匹配失败(开发环境警告,不注入)。

Writing modifiers / 编写 modifier

A modifier receives the final selector and the CSS declaration, and returns a full rule:

modifier 接收最终选择器与 CSS 声明,返回完整规则:

const modifiers = {
  dark: (selector, cssDecl) => `.dark ${selector} { ${cssDecl} }`,
  maxLg: (selector, cssDecl) => `@media (max-width: 1024px) { ${selector} { ${cssDecl} } }`,
};

Extending the default preset / 扩展默认预设

createConfig accepts recursive overrides: objects merge key by key (defaults survive), functions and other values replace wholesale, null deletes a key. The engine treats any non-function non-object value as "key absent", so deletion needs no special case.

createConfig 支持递归覆盖:对象逐键合并(默认键保留),函数与其他值整体替换,null 删除键。引擎把非函数非普通对象的值一律视为"键不存在",删除因此无需特判。

import { createRox, createConfig } from "roxcss";

const rox = createRox(
  createConfig({
    modifiers: {
      lg: (selector, cssDecl) =>
        // override / 覆盖默认的 min-width 语义
        `@media (max-width: 1024px) { ${selector} { ${cssDecl} } }`,
    },
    matchers: {
      // merge into the default flex subtree / 合并进默认 flex 子树
      flex: { half: () => "flex:1 1 calc(50% - 8px)" },
      // replace a whole subtree / 整体替换某子树
      shadow: () => "box-shadow:var(--shadow)",
      // delete a root / 删除某个根
      animate: null,
    },
  }),
);

Working with CSS variables / 配合 CSS 变量

roxcss does not interpret values, so CSS variables compose naturally. A common pattern is a private helper that turns segments into a var() reference:

roxcss 不解析值,CSS 变量因此天然可组合。常见做法是私有 helper 把段拼成 var() 引用:

// segments → var(--accent-bg) / 段 → var(--accent-bg)
const cssVar = (vs: string[]) => `var(--${vs.join("-")})`;

createRox(
  createConfig({
    matchers: {
      color: (...vs) => `color:${cssVar(vs)}`,
      bg: (...vs) => `background:${cssVar(vs)}`,
      border: {
        color: (...vs) => `border-color:${cssVar(vs)}`,
        t: () => "border-top:1px solid var(--border)",
      },
    },
  }),
);

Default Preset / 默认预设

The default preset borrows its vocabulary from Tailwind v4 — the same utility names, the same nesting — so familiar classes keep their meaning. Two conventions differ from Tailwind, and knowing them once is enough to read everything below:

默认预设的词汇取自 Tailwind v4——相同的工具类名、相同的嵌套结构——熟悉的类名含义不变。两处约定与 Tailwind 不同,先了解它们,下面的示例就都能读懂:

Values carry their units / 值自带单位

roxcss has no numeric scale: p-4 does not mean 1rem as it does in Tailwind. Write the full value and it lands in the declaration verbatim — p-4pxpadding:4px, w-170pxwidth:170px. A bare number produces invalid CSS; that is a caller error.

roxcss 没有数值刻度:p-4 不像在 Tailwind 中那样表示 1rem。单位写全,值原样进入声明——p-4pxpadding:4pxw-170pxwidth:170px。裸数字会生成无效 CSS,属调用方错误。

text is size, color is color / text 管字号,color 管颜色

Tailwind overloads text-* for both sizing and coloring; roxcss keeps them apart — text-16px sets font-size, color-red sets color.

Tailwind 用 text-* 兼任字号与颜色;roxcss 分开处理——text-16px 设置字号,color-red 设置颜色。

Utilities by category / 按类别示例

The preset covers layout, spacing, typography, borders, colors, and effects. A selection follows, grouped by category; the full listing lives in docs/预设设计.md.

预设覆盖布局、间距、排版、边框、颜色与效果。以下按类别节选,完整清单见 docs/预设设计.md

Layout / 布局

flex              → display:flex
flex-col          → display:flex;flex-direction:column
grid-cols-3       → display:grid;grid-template-columns:repeat(3,minmax(0,1fr))
items-center      → align-items:center
justify-between   → justify-content:space-between
gap-16px          → gap:16px
p-24px            → padding:24px
w-170px           → width:170px

Typography / 排版

text-16px         → font-size:16px
text-center       → text-align:center
font-bold         → font-weight:700
leading-16px      → line-height:16px
underline         → text-decoration-line:underline
truncate          → overflow:hidden;text-overflow:ellipsis;white-space:nowrap

Borders, colors & effects / 边框、颜色与效果

rounded-5px       → border-radius:5px
border-2px-solid-red → border:2px solid red
bg-blue           → background:blue
color-red         → color:red
duration-150ms    → transition-duration:150ms
delay-75ms        → transition-delay:75ms

Position, overflow & more / 定位、溢出与其他

relative          → position:relative
inset-x-0         → inset-inline:0
z-10              → z-index:10
overflow-x-auto   → overflow-x:auto
hidden            → display:none
list-none         → list-style:none
aspect-16/9       → aspect-ratio:16/9

Families share a pattern: every side and axis variant exists — m mirrors p, overflow-y mirrors overflow-x, and so on.

工具类家族遵循同一模式:每个方向与轴向的变体都存在——mp 对应,overflow-yoverflow-x 对应,依此类推。

Breakpoints come from createModifiers() with defaultBreakpoints, all min-width media queries. Prefix a class name with a breakpoint and it applies from that width up:

断点由 createModifiers() 基于 defaultBreakpoints 生成,全部为 min-width 媒体查询。在类名前加断点前缀,规则从该宽度起生效:

<div class="flex-col lg:flex-row">…</div>

Framework Usage / 框架用法

Because class names are returned as plain strings, any class binding works. The string can be produced anywhere — a computed property, an inline handler, or a plain function — and handed to a framework's binding. A Vue example:

类名以普通字符串返回,因此任何 class 绑定方式都适用。字符串可以在任何位置生成——computed、事件处理器或普通函数——再交给框架的绑定。Vue 示例:

<script setup lang="ts">
import { rox } from "./rox"; // your configured instance / 你配置好的实例
</script>

<template>
  <button
    type="button"
    :class="
      rox`inline-flex font-mono text-16px px-10px rounded-5px
           hover:bg-blue focus-visible:bg-blue`
    "
  >
    Click me
  </button>
</template>

Performance & Injection / 性能与注入

  • Batch flush per call. All new rules from one call are appended to the active <style> bucket in a single textContent write — one parse, one style invalidation. No per-rule insertRule (measured O(N²) under interleaved forced layout; see 性能分析.md).

  • Rolling style buckets. The active <style data-roxcss> element is reused until it holds 1000 rules, then frozen and a new one is created. Bucket count stays at ceil(rules / 1000) — no DevTools panel clutter.

  • SSR safe. With no DOM, rules are kept in memory and readable via getCSS().

  • 每次调用批量写入:一次调用产生的新规则,以一次 textContent 赋值追加到活动 <style> 桶——一次解析、一次样式失效。不使用逐条 insertRule(实测在交替强制布局场景退化为 O(N²),见 性能分析.md)。

  • 滚动 style 桶:活动 <style data-roxcss> 元素复用到 1000 条规则后冻结,新建下一个。桶数保持在 ceil(规则数 / 1000)——DevTools 面板不堆积。

  • SSR 安全:无 DOM 时规则保存在内存,经 getCSS() 读取。

Docs / 设计文档

The design docs are written in Chinese and archived under docs/:

设计文档以中文撰写,归档在 docs/

| Doc / 文档 | Content / 内容 | | ------------------------------------------------- | --------------------------------------------------- | | 设计方案.md | Engine architecture, token parsing, matcher lookup. | | | 引擎架构、token 解析、matcher 查找。 | | 预设设计.md | Default preset design and full utility listing. | | | 默认预设设计与完整工具类清单。 | | 样式表管理策略.md | Rolling <style> bucket injection design. | | | style 滚动桶注入设计。 | | 性能分析.md | Performance model and measurements. | | | 性能模型与实测。 | | tailwind对齐计划.md | Tailwind v4 alignment decisions and gaps. | | | Tailwind v4 对齐决策与差距。 |