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/preset-standard

v0.8.1

Published

The standard utility vocabulary for TeaCSS — spacing, sizing, color, layout, typography, and more.

Readme

@teacss/preset-standard

The standard TeaCSS utility vocabulary, theme, conditions, and preflight.

Standard intentionally owns no shortcuts. Define product compositions with @shortcut or enable @teacss/preset-official separately.

Usage

bun add @teacss/preset-standard
@presets "standard";
@source "./src/**/*.{ts,tsx}";
@teacss;

Programmatic consumers use presetStandard(). Public value tables are available from @teacss/preset-standard/constants:

import {
  boxDecorationValues,
  globalKeywords,
  multiplierKeywords,
} from "@teacss/preset-standard/constants";

Each *Values export contains common property values. CSS-wide keywords are separate. Use multiplierKeywords for the numbered scale.

Application shortcuts

@shortcut stack-row "d:flex flex-direction:row ali:center";
@shortcut text-truncate "overflow:hidden text-overflow:ellipsis white-space:nowrap";

Declarations may live in the CSS entry, imported CSS, or CSS matched by @source. Conditions remain valid on use, and the last declaration of a name wins. Programmatic shortcuts use Core's generic UserConfig types.

Paired sizing and logical dividers

For text-flow sizing, size:4x, min-size:4x, and max-size:4x set both inline and block sizes. For fixed geometry, use dimensions:4x, min-dimensions:4x, and max-dimensions:4x for width and height. These are ordinary Standard declarations. Values must be accepted by both underlying single-axis rules. Variables, arbitrary values, and suffix conditions work as they do on those rules. size:screen emits 100vi and 100vb; dimensions:screen emits 100vw and 100vh.

divide-inline-width: and divide-block-width: draw on logical inline-end and block-end edges. divide-x-width: and divide-y-width: keep physical right and bottom edges. divide-color: and divide-style: supply common settings. divide-inline-color/style: and divide-block-color/style: override only the named logical axis. Color and style alone do not draw a divider; each axis needs its own width. To change axes at a breakpoint, set the old width to 0 and the new width explicitly.

Preflight and themes

Preflight emits low-specificity reset rules and theme variables. The default, preflight: "on-demand", limits variables to referenced keys (including the reset's sans and monospace families). Set preflight: true to emit every theme and @custom variable for CSS or inline styles that read them directly, or preflight: false to disable both.

Selecting @presets "standard" also normalizes headings, links, lists, media, tables, horizontal rules, code typography, and form-control typography. Headings inherit size and weight; links inherit color and decoration; lists lose their markers; images and videos fit their container without losing aspect ratio. Use utilities or Official's prose family to author their visible presentation.

Small text, sub/sup, titled abbreviations, and progress have consistent baselines. Dialogs and popovers retain native auto-margin centering after the universal spacing reset; opening and closing remain browser-controlled. File-selector buttons inherit input typography and color while keeping native appearance. Fieldsets use min-inline-size: 0 so their boxes can shrink inside narrow containers; oversized descendants still need responsive sizing. Grouped options in select[multiple] and select[size] retain a 20px inline-start indent, following text direction and allowing utility overrides. The reset enforces native hiding with two global rules:

:where([hidden]:not([hidden="until-found" i])) { display: none !important; }
:where([hidden="until-found" i]) { display: revert !important; }

Ordinary display utilities, component CSS and inline styles cannot reveal an element with hidden; remove the attribute to show it. Explicit !important declarations still follow the CSS cascade. until-found restores the tag's native display, with discovery depending on the tag and browser. Prefer div or section containers for discoverable content:

<section hidden="until-found">Searchable content</section>

These rules run in both full and on-demand preflight. With preflight disabled, the application supplies its own hiding rules.

Native control appearance, focus outlines, disabled state, and disclosure behavior remain intact. Marker-free semantic lists should use role="list" for Safari/VoiceOver. The reset adds no brand palette or global motion policy. Element-local reset-* shortcuts belong to the optional Official preset; Standard does not register those classes.

Global role palettes and color scheme

Standard has seven roles: primary → ink, neutral → gray, focused → neutral, success → jade, warning → amber, failure → red, and general → blue. Use numbered roles directly, such as bg-color:primary-800 text-color:primary-000; steps follow Radix's layout: 100–400 backgrounds, 500–700 borders, 800/850 solids, 900/950 text. 000 is the text on 800/850, Radix's contrast color: white for most families, dark for sky mint lime yellow amber, and flipping with ink. A family without 000 resolves <family>-000 to white. Official adds structure without background/hover/foreground color aliases.

Each use writes one step for both modes; when a pair misses contrast, the palette changes, not the class. Neutral builds structure with every step: page 150, panels 100 without borders, hover 300, borders 500–700. Signal roles appear only in a few forms. Primary: the brand face (800 + 000, one button per view), the value (900 for links, icons, indicators and checked fills, with neutral-100 marks), and selection (200, 300 hovered, text 950). States: the value (900 for text, icons and validation borders), the soft badge (200 + 950), and the strong face (900 + neutral-100, 950 hovered). 900 + neutral-100 reaches 4.5:1 for every family; 800 + 000 reaches Radix's 3:1. Alpha serves only disabled text (neutral-900/60) and scrims. Charts write dictionary names, such as fill-color:office-900; the entry dictionary binds office to indigo.

ink is a complete 12-step physical palette in both modes: gray surfaces, near-black light-mode and near-white dark-mode 800/850 fills, and 900/950 text. Consume it through primary; it adds no role. gray and sage remain available. Absent role attributes use ink/gray defaults without candidate lists. Explicit html selections, including ink, still require the corresponding role list.

lime uses Yiplex's brand lime in the standard step layout. Its 800 solid is #BAC836 (#C6D43B in dark mode) with 850 on hover; lime-000 is the dark moss text for both modes. 900/950 are olive and moss text.

The CSS entry registers the selectable built-in physical palettes:

@presets "standard,icons,official";
@primary "ink,gray,gold,red,blue";
@neutral "gray,sage,slate";
@custom focused "primary";
@success "jade,green";
@warning "amber,orange";
@failure "red,ruby";
@general "blue,cyan";
@teacss;

Repeated/imported lists union and sort. They enable choices without changing defaults; removing every list for a role clears its choices. Only Standard's original built-in physical palette names are candidates. Overrides through @custom or theme.colors keep that identity; custom names remain available to ordinary color utilities but cannot become role candidates. Enabled palettes need all 12 effective steps and no direct/transitive role references, including mode overrides, preflightBase, and variable fallbacks. Candidate registration has no public Theme field; programmatic consumers load the CSS entry with resolveEntryConfig().

<html data-css-primary="blue" data-css-neutral="slate" data-css-appearance="dark">
  <body><p class="text-color:primary-900">Global blue / slate / dark</p></body>
</html>

Only html role attributes, data-css-appearance and configured mode aliases select colors. Descendants inherit; the same markers on descendants have no effect. Missing, empty, unknown or undeclared role values use configured defaults. Focused defaults to final global neutral while preserving explicit default step overrides. The site may bind focus once with @custom focused "primary";, "neutral" or a complete palette. @focused lists are removed; data-css-focused has no effect. The other six roles retain their selectable lists. Changing root attributes switches registered candidates without regenerating CSS.

@dark / @light inspect html for every final target, including pseudo-elements. Without a valid explicit mode, neither condition activates, even when defaultMode is dark; defaultMode names the base table. OS conditions remain independent media queries. modeSelectors: { dark: ".night", light: ".day" } adds optional aliases on html. Canonical data-css-appearance wins even when empty/invalid; conflicting aliases select neither mode. Aliases are never implicit. Mode names preserve case, spaces and punctuation; empty names, NUL and unpaired surrogates are invalid.

Theme output uses zero-specificity ordinary html selectors: base variables once, mode differences, then independent role mappings. Each role/candidate mapping is emitted once, without multiplying it by modes or other roles. preflightRoot adds explicit re-declaration targets that always use html selections; it does not enable local colors. On-demand preflight retains the consumed dependency closure through all registered candidates and effective modes. With preflight disabled, root mode conditions still work but the application supplies variables.

Global @custom sets scales and colors; @custom dark changes colors only. Whole-theme variants and role scheme blocks are unsupported. Color selection never resets inherited spacing or changes radius/shadow geometry.

Root distances

--spacing is the only distance knob; default named steps derive from it:

--spacing: 0.25rem;
--spacing-1x: var(--spacing);
--spacing-5x: calc(var(--spacing) * 6);

Override it on html, such as $spacing:0.125rem@sm, to change numeric and default named spacing; named multipliers remain 1,2,3,4,6,8,10,12,16. For a whole-page size change use browser zoom or the root font size: every scale is rem-based. --scaling was removed in 0.7.2 for that reason. Explicit named overrides remain final values; reference --spacing to make a custom step follow. Variables resolve where declared, so a descendant-only override does not recompute inherited root spacing. --T-radius-factor (default 1) is the only shape knob. Data-dense screens use explicit density classes, not multipliers; see the Skill's density rules.

The default sans stack is IBM Plex Sans followed by PingFang SC, Hiragino Sans GB, Microsoft YaHei, Source Han Sans SC and Noto Sans CJK SC; mono ends with PingFang SC, Microsoft YaHei and Noto Sans CJK SC before monospace.

Relationship markers

data-css-group enables anonymous ancestor conditions such as @group-hover; data-css-peer enables preceding-sibling conditions such as @peer-checked. Named values are ASCII-whitespace-separated lists: data-css-group="card panel" also enables @group-hover/card and @group-hover/panel. Presence always matches anonymous conditions; an empty value enables only anonymous ones. Names are case-sensitive. Group remains descendant matching, peer uses ~.

Root language conditions

<html lang="zh">
  <body><p lang="en" class="p:4 p:10@lang-zh">...</p></body>
</html>

@lang-<tag> compares the complete root html:root[lang] value, ignoring ASCII case without trimming. Here @lang-zh matches and @lang-en does not. zh, zh-CN, and zh-Hans are independent: @lang-zh does not match a root value of zh-CN. Local lang and descendant color markers do not override the root language. Root elements, descendants, targets, and pseudo-elements share this condition.

Use BCP 47 tags: zh, zh-CN, zh-Hans, zh-Hans-CN, es-419, de-1996, and en-u-ca-gregory. Extlang, private-use (x-project), and grandfathered (i-klingon) forms are also supported. Validation checks structure, not registry membership; it does not canonicalize aliases or infer parent tags. Tag case is unrestricted: @lang-zh-CN and @lang-zh-cn match identically. Non-ASCII characters, malformed subtags, underscores, whitespace, wildcards, and escapes are unmatched. The lowercase lang- prefix is reserved: rename custom breakpoint keys using it, including invalid language forms. Existing @max-<name> syntax is unchanged.

@!lang-en also matches missing/empty root language. Conditions compose with states, relations, queries, modes, targets, shortcuts, and @apply using AND. Conflicting languages never match; repetition follows ordinary suffix behavior. The language guard contributes 0,1,0 specificity before existing wrappers; space-* / divide-* keep their zero-specificity selectors.

Changing root lang updates generated CSS without runtime listeners or regeneration, including with preflight disabled. Keep complete tokens in scanned sources or safelists; do not escape @ in HTML/JSX class strings. Each HTML iframe uses its own root; propagation across Shadow DOM or independent XML documents is unsupported. Applications own translation, dir, and SSR's initial language.

Class merging

import { cn } from "@teacss/classes";

cn("p:4 d:flex", "p:8"); // "d:flex p:8"
cn("p:4", "p:invalid"); // "p:invalid"
cn("p:2@lang-en", "p:4@lang-en"); // "p:4@lang-en"
cn("p:2@lang-ZH", "p:4@lang-zh"); // "p:4@lang-zh"

cn uses fixed Standard and Icons rules. Install and import @teacss/classes directly for runtime class composition. Merge uses prefix shape and ordered conditions, ignoring ASCII language-tag case while preserving each winning token's spelling. It does not validate values or condition support: malformed suffixes can merge but emit no CSS. Unknown declarations merge only by their own prefix; application shortcuts have no cross-prefix footprint.

Native shorthands are emitted before their component overrides. For example, cn("border:[1px_solid_red]", "border-t-width:4") retains both classes and produces a 4px top border. Reversing those arguments leaves only the shorthand. The same ordering covers place/gap/columns, text families and corner shapes; explicit display and overflow can override line-clamp's corresponding declarations. animation-composition: stays independent of animation: in either input order; merging a named animation preserves its additive or accumulating behavior.

Source and condition boundaries

space-* conditions, including conditions on enclosing shortcuts and reverse activators, target the container. Conditional spacing overrides its default even when the requested distance is smaller; child-local margin utilities still win against the zero-specificity container rules.

Named container queries require a valid container name. CSS-wide keywords, default, none, and, or, and not are rejected, including escaped or case-varied spellings, rather than becoming anonymous queries.

The ! suffix marks the declaration important even when its value contains the literal text !important. Quoted text and function arguments are not priorities.

The default :css: transformer decodes static JS/TS string escapes once before compilation. JSX/HTML attribute values and String.raw retain their CSS escapes. Dynamic template literals are left unchanged; use complete static strings for compiled classes. Kept unknown classes are escaped back into the original JS quote.

Value and composition boundaries

  • Logical border width/style pairs accept two arbitrary components, such as border-inline-width:[1px_2px]; physical x/y and single-edge forms accept one.
  • […] keeps structurally valid arbitrary CSS, including animation-name:[var(--name)]. It does not guarantee browser support.
  • Custom-variable values and font-palette use the shared structural checks; failed bracket/variable decoding cannot fall back to unchecked raw CSS.
  • A configured DEFAULT key references its unsuffixed variable: p:DEFAULT reads --spacing, including through negative spacing. Applications supply these scale variables when preflight is disabled.
  • Named shadows use global templates and support local color overrides. shadow:$shadow-card reads a complete raw variable without recoloring; box-shadow:[…] replaces the whole composed surface. box-shadow:none clears that surface, including shadow outlines, when it wins the cascade; shadow:none and inset-shadow:none clear only their respective slots.
  • Named animations quote their decoded CSS names to avoid shorthand keyword ambiguity. Numeric zero iteration counts remain zero. animation:spin rotates at 1s linear infinite; animation:spinner fades a spinner leaf from opacity 1 to .25 at 800ms linear infinite. Duration, timing, and iteration utilities override these defaults. Gate decorative motion with @motion-safe or stop it with animation:none@motion-reduce.
  • Bare background/mask sizes cannot be negative.
  • Border-spacing axis variables do not inherit into nested tables.
  • Gradient properties are registered on demand, retaining shared fallbacks and neutral additive-mask layers without registering unrelated families.

Explicit activators

Standard utilities all use property:value. The following activators accept exactly on, with ordinary importance and suffix conditions:

mask-g-linear:on mask-g-radial:on mask-g-conic:on
space-x-reverse:on space-y-reverse:on space-inline-reverse:on space-block-reverse:on

Use divide-x-width:1 / divide-y-width:1 for 1px child dividers. The former nine bare spellings emit nothing; bare names are reserved for registered application or Official shortcuts. Removing an activator restores its default; off, true, variable, arbitrary, and CSS-wide values are unsupported.

Pre-1.0. Keep tests and documentation aligned when changing vocabulary.

Data dictionaries and reports

@custom office "indigo"; registers 13 alias steps (including 000 with white fallback), preserving on-demand reference closure and global mode values. Write bg-color:office-900 or fill-color:office-900/50@hover; keep physical families in the dictionary. Targets require 12 effective steps and cannot be aliases; focused alone may follow primary/neutral. Per-step and mode blocks remain available for overrides. Config owns validation and editor source ranges.

State needs an action or judgement and text. Category uses a fixed dictionary name/order; quantity uses a sequential meaning, direction a site-defined pair. Reports share those meanings, numbers, units, global mode and font. They use one neutral-100 surface, neutral-500 section lines, prose-hans paragraphs, 32px tables outside prose and directly labelled charts, without primary, controls or compact.