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

@teacss/classes

v0.8.1

Published

TeaCSS class composition — typed recipes, nested class-value joining, and semantic conflict resolution.

Readme

@teacss/classes

Typed class composition and vocabulary-aware conflict resolution.

This package owns the fixed cn and recipe runtime for Standard, Icons and Official's eighteen numbered typography names. The teacss development tool does not re-export these helpers. Classes do not generate CSS or validate utility values; merger plugins and custom conflict configuration are not supported.

Recipes

A string defaults defines a single-element recipe. Calling it returns a merged string and accepts a caller override:

import { recipe, type ClassProp, type VariantProps } from "@teacss/classes";

const badge = recipe({
  defaults: "d:inline-flex ali:center p-x:2",
  variants: {
    tone: {
      neutral: "bg-color:neutral-200 text-color:neutral-950",
      accent: "bg-color:primary-800 text-color:primary-000",
    },
  },
  defaultVariants: { tone: "neutral" },
});

badge({ tone: "accent", className: "p-x:3" });

type BadgeProps = VariantProps<typeof badge> & ClassProp;

defaults supplies base styles, variants supplies additional styles when a choice is selected, and defaultVariants selects the component's initial conditions. Omitted selections use defaultVariants; null disables a selection.

An object defaults defines named elements. Every key is ordinary; root is not required or special. The recipe call selects shared variants and returns one resolver per key. Caller className belongs to a resolver, not the recipe call.

const button = recipe({
  defaults: {
    container: "d:inline-flex ali:center p:2",
    icon: "inline-size:4x",
  },
  variants: {
    size: {
      small: { container: "p:2", icon: "inline-size:3x" },
      large: { container: "p:4", icon: "inline-size:5x" },
    },
  },
  compoundVariants: [
    {
      size: "large",
      classKeys: ["container", "icon"],
      className: "opacity:80",
    },
  ],
});

const classes = button({ size: "large" });
classes.container({ className: "p:6" });
classes.icon();

Multi-element choices target named elements with maps. A compound uses either a className target map or a string className plus a non-empty, unique classKeys list. The forms cannot be combined. class, className, and classKeys are reserved variant names.

A one-sided boolean variant supports the undeclared opposite boolean as a branchless state. The corresponding string is not an alias. Keep responsive behavior in class conditions such as p:4@md, not variant objects.

Recipes may extend one parent created by the same loaded classes module. A child may inherit defaults, but an explicit value must preserve the parent's string or object mode.

Shared recipe identity

Recipe libraries should peer-depend on and externalize @teacss/classes so parents and children use the same loaded module. Two physical classes copies have separate private registries and reject cross-copy extension. Copying a recipe's frozen .config cannot forge its identity. VariantProps is type-only and can infer types across package copies.

Class merging

bun add @teacss/classes
import { cn, type ClassValue } from "@teacss/classes";

const caller: ClassValue = ["p-x:8!", { "d:flex": true }];
cn("p:4", caller); // "p:4 p-x:8! d:flex"
cn("p:4", "p:invalid"); // "p:invalid"
cn("icon:bad icon:other icon:bad"); // "icon:bad"

cn accepts nested class values, own enumerable truthy dictionary keys, tagged templates, numbers, bigints, and falsy branches. Ordinary 0 and 0n are ignored; template interpolation preserves them. Getters run on each call and user exceptions propagate unchanged. Invalid array lengths throw TypeError.

Only tokens with identical ordered conditions can conflict; complete language-tag payloads in lang- / !lang- compare without ASCII case. For example, cn("p:1@lang-zh-CN", "p:2@lang-zh-cn") returns "p:2@lang-zh-cn". Winning tokens retain their spelling, including unsupported conditions; use complete BCP 47 tags for CSS generation. zh, zh-CN, and zh-Hans have separate identities. A later token can remove a fully covered earlier token; an important token wins only over effects it covers. Fixed composite-property exceptions preserve filter, shadow, scrollbar, transform, image, and gradient behavior. Surviving raw tokens retain their order.

The dimensions, min-dimensions, max-dimensions, size, min-size, and max-size declarations also accumulate coverage from their two matching axes. For example, cn("dimensions:4x", "w:8", "h:10") returns "w:8 h:10", while cn("size:4x", "inline-size:8") retains both tokens. Important axes may win before or after the combined token. Physical/logical and preferred/min/max groups stay independent. Other properties keep pairwise coverage: cn("p:1", "p-x:2", "p-y:3") retains all three.

All icon:value declarations merge by the icon prefix without validating the value: the last icon wins under identical ordered conditions and importance. Unknown declarations also merge by prefix. The eighteen exact bare names text-1x through text-9x and heading-1x through heading-9x share one fixed keyword group. Within identical ordered conditions, the last token at equal importance wins across both families; an important token wins over an ordinary one in either order. Other bare names, including icon, retain separate keyword identities. Custom CSS rules and shortcuts remain available to the generator; their cross-prefix conflicts are not inferred by classes.

cn("text-3x", "text-5x"); // "text-5x"
cn("text-3x", "heading-5x"); // "heading-5x"
cn("text-3x!", "heading-5x"); // "text-3x!"
cn("text-3x@sm", "heading-5x@sm"); // "heading-5x@sm"
cn("text-3x", "heading-5x@sm"); // "text-3x heading-5x@sm"
cn("text-3x", "font-size:5x"); // "text-3x font-size:5x"

Recipes apply the same typography group to defaults, variants, compounds and caller overrides. Recognition does not depend on enabling Official; CSS generation still requires the relevant presets. Classes does not expand shortcuts: atomic font-size:, letter-spacing: and line-height: declarations are retained alongside numbered typography in either order, even when all three are supplied. Their CSS layers, conditions and importance determine overrides. Semantic names such as text-body, out-of-range steps and colon declarations are outside the numbered group.

Keep original fragments until one final merge. A survivor string loses sequence information, so nested merges need not equal one flat call. Recipes retain fragments through extension and merge once per resolved element; safe static fragments reuse parsed tokens without pre-merging them.

Caches are bounded private implementation details. They preserve object getter reads, ordered conditions, and success/error behavior; no cache options are part of the public API.

The exports are cn, recipe, omitAttributes, and the types ClassDict, ClassValue, Merger, ClassProp, RecipeIntrospection, Reciper, VariantProps. Merger and Reciper describe callable interfaces, not configurable factories.

For applications using earlier factories or preset-only entries, see the 0.5.2 to 0.6.0 migration.

Pre-1.0. Public recipe and merge APIs may change before the stable release.