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

grammar-style

v0.6.1

Published

A zero-runtime token resolution engine for design systems.

Readme

Build your design tokens once, and map them instantly into your favorite styling tools with strictly typed, auto-completing safety. Stop writing runtime token interpolations and embrace statically generated, strictly verified CSS variables.

📖 Table of Contents

🚀 Getting Started

npm install grammar-style

Generate a grammar.config.ts boilerplate file right in your project:

npx grammar-init

If you are using strict zero-runtime sandboxed libraries (like Linaria or Vanilla Extract) and want to use the global media exports, generate your cached tokens:

npx grammar-style generate

💡 Pro-Tip: Chain the Generator! Because media breakpoints are globally cached in your node_modules, you should automate this. Add it to your package.json scripts so they regenerate automatically every time you start your development server!

{
  "scripts": {
    "dev": "grammar-style generate && <your-framework-dev-command>",
    "build": "grammar-style generate && <your-framework-build-command>"
  }
}

📓 Concept: defineGrammar

The core of grammar-style is defineGrammar, the typed definition engine. Design systems often suffer from disconnected tokens across different surfaces. defineGrammar forces your config to strongly adhere to two layers: Primitives and Semantics.

  • Primitives are raw values (your Hex hues, absolute spacings, etc).
  • Semantics are contextual mappings describing how those primitives apply to your UI (e.g. brand.primary).

By enforcing this separating structure, any invalid mapping simply fails your TS compiler!

import { defineGrammar } from "grammar-style"

export const config = defineGrammar({
  primitives: {
    color: {
      stone: {
        900: "#1A1A1A",
        100: "#E6E6E6",
      },
      brand: "#FF007F",
    },
  },
  semantics: {
    color: {
      background: "color.stone.100",
      surface: "color.stone.900",
      primary: "color.brand",
    },
  },
})

// Binds autocomplete safely everywhere
declare module "grammar-style" {
  export interface Register {
    theme: typeof config
  }
}

⬆️ Back to Top

📏 Built-in Primitives: size

The size primitive is special. It acts as a pre-populated grid scale built perfectly around strict UI layouts.

The px to rem Bridge

You access tokens using developer-friendly pixel numbers (e.g. size.16), but the compiled output strictly emits natively responsive rems (1rem). This gives you the mental clarity of working with absolute layouts without sacrificing the fluid scalability and accessibility of generic rem units.

Allowed Constraints

Grid sizes map tightly. Small sizes allowed are: 1, 2, 4, 6, 8, 10, 12, 16. Beyond that, all sizes must be multiples of 4 up to 3000. You can't enter size.15 as it breaks the rules of structural scaling!

Mathematical Negatives

grammar-style uniquely supports dynamic negative polarity without duplicating tokens.

-size.16 natively compiles directly to literal math without CSS variables: -1rem

Zero-Bloat CSS

Instead of injecting 700+ size variables into global CSS which balloons performance, or relying on complex background file scanners, grammar-style inherently bypasses the CSS Variable map completely for dimension primitives. It perfectly evaluates your target layout integers directly into strict literal math inline natively (token("size.16") evaluates instantly to strictly "1rem"). Your :root CSS stays completely empty of size primitives, ensuring lightning-fast static performance.

⬆️ Back to Top

🎛️ Options

The options block lets you overwrite the core rules of your token validation.

| Option | Default Value | Description | | :--------------- | :--------------------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | opacities | [10, 20, 40, 60, 80, 100] | Restricts allowed transparency fractions. Supply an array of mapping numerals (e.g. [10, 50]) to redefine opacity strings natively (/10, /50) across your semantic object bindings. | | breakpoints | sm: "size.640"md: "size.768"lg: "size.1024"xl: "size.1280"xxl: "size.1536" | Standard responsive layout endpoints. Implicitly generates Max variants for every key natively (e.g. lgMax safely maps to scaling rem math emitting max-width: calc(64rem - 1px) to avoid cross-breakpoint layout collisions natively). Map exclusively to custom size.* primitives to override. | | modes | ["dark", "light"] | Strings enforcing structurally validated root wrapper themes mapping safely toward conditional CSS elements natively like [data-theme="dark"]. | | useStrictSizes | true | Enforces mathematical constraints (size.4, size.16). Passing false removes geometric compilation locks, allowing arbitrary tokens like size.15 to be safely passed anywhere inside your configuration or token("size.15") utility seamlessly without breaking Type-Checking. |

import { defineGrammar } from "grammar-style"

export const config = defineGrammar({
  options: {
    // Customizes the opacity scale to allow /5 and /50 fractions
    opacities: [5, 10, 20, 40, 50, 60, 80, 100],
    // Allows deep validation for explicit alternative root subsets
    modes: ["dark", "light", "high-contrast"],
    // Overrides default layout boundaries perfectly mapped to structural `size.*` grids
    breakpoints: {
      md: "size.800",
      lg: "size.1000",
      xl: "size.1200",
    },
  },
  // ...
})

Overriding Breakpoints

If you override a natively defined breakpoint key (e.g. lg: "size.1400"), grammar-style perfectly preserves all other structural keys while safely calculating and generating your new lgMax fluid mapping fallback locally!

However, if your configuration injects custom keys completely ignoring the native boundaries (e.g. palm: "size.600"), the compiler intelligently infers that you want to rewrite your layout rules from scratch. It effortlessly builds and spins up your custom palmMax scaling, but fully purges the standard sm, md, lg targets. This gives you a pristine Typescript autocomplete interface completely devoid of bloat or leftover unused defaults.

⬆️ Back to Top

🧱 Primitives

The foundation structural layer. Here you dictate your hardcoded absolute properties—like your hex swatches (#ff0000), spacing logic, or unconstrained radii layers. You map these as standard nested objects (e.g. border: { radius: "size.24" }).

⚠️ Size is Geometrically Locked: The built-in size primitive dictionary serves as a structural foundation explicitly designed to keep scaling aligned perfectly to UI layout box models. Passing { size: { ... } } internally inside your primitives overrides will strictly trip an architectural compiler lock forcing a local build crash.

export const config = defineGrammar({
  // ...
  primitives: {
    color: {
      stone: {
        900: "#1A1A1A",
        500: "#808080",
        100: "#E6E6E6",
      },
      brand: "#FF007F",
    },
    shadow: {
      soft: "0 size.4 size.12 -size.4 color.stone.900/10",
      hard: "0 size.8 size.24 color.stone.900/25",
    },
  },
  // ...
})

⬆️ Back to Top

🧠 Semantics

Your contextual intent mapping. Semantic mappings cannot resolve to hardcoded string strings—they must actively route to valid underlying Primitive dot-paths.

Deep Nesting

Configure categorized hierarchies to build logical taxonomies like primitives.color.blue.900. The TS compiler elegantly tracks every deeply nested layer natively, strictly enforcing your semantic lookups via concatenated dot.path string identifiers (e.g. "color.blue.900").

Dynamic Color Opacities

You can invoke opacity fractions directly on your token paths. For example, mapping "color.brand/50" automatically converts the underlying primitive to an rgba() CSS variable with 0.5 opacity statically.

export const config = defineGrammar({
  //...
  semantics: {
    color: {
      surface: {
        // Evaluate into deep mapping layers effortlessly!
        elevated: "color.stone.900",
        inset: "color.stone.100",
      },
      // You can mix and match custom deeply nested paths alongside logic tokens seamlessly
      text: {
        muted: "color.stone.500",
        accent: "color.brand/50",
      },
    },
  },
})

⬆️ Back to Top

🌓 Modes

Use the modes object to map dark mode, high contrast, or unique theme variants natively. Simply provide a TypeScript-enforced deep-partial of your semantics object inside modes: { dark: { ... } }. grammar-style will automatically emit these overrides bound tightly behind native [data-theme="dark"] { ... } wrappers in your CSS output.

export const config = defineGrammar({
  //...
  modes: {
    // Automatically wraps CSS emissions in [data-theme="dark"]
    // Deep validations bind ensuring you match the identical nested structure found in semantics!
    dark: {
      color: {
        surface: {
          elevated: "color.stone.100", // Strict primitive dot-path boundary checks
          inset: "color.stone.900",
        },
      },
    },
  },
})

⬆️ Back to Top

📱 Responsive

Handle media queries across standardized boundaries by partially overriding semantics exactly like modes.

export const config = defineGrammar({
  //...
  semantics: {
    spacing: {
      base: "size.24",
      half: "size.12",
      double: "size.48",
    },
  },
  responsive: {
    // The `<key>Max` sub-variant was natively mapped and injected!
    mdMax: {
      spacing: {
        base: "size.20",
        half: "size.10",
        double: "size.40",
      },
    },
    // The explicit endpoint targets `@media (min-width: ...)` maps exactly as expected!
    lg: {
      spacing: {
        base: "size.32",
        half: "size.16",
        double: "size.64",
      },
    },
  },
})

⬆️ Back to Top

🎨 The Power of token()

Once your grammar is defined, you'll need to safely consume those tokens inside your standard components. The token() utility translates your Typescript semantic paths exactly into the native CSS variables grammar-style constructs under the hood.

Why use it?

  • 100% Type-Safe: It throws compilation errors if you misspell a path, preventing "silent styling failures."
  • Zero Runtime Overhead: It evaluates tokens synchronously into native declarative CSS var() maps.
  • Dynamic Opacities & Native Math: You can composite standard CSS expressions natively inside a single string (token("color.brand/50"), token("-size.400"), or even isolated functions like token("calc(size.400 * 2)")). The engine safely parses, resolves, and constructs the necessary variable structures during compilation without bloating your DOM with extra utility classes!

1. Template Strings (Linaria, Styled Components, Emotion)

const Box = styled.div`
  /* Emits: rgba(var(--color-surface-rgb), 0.5) */
  color: ${token("color.surface/50")};

  /* Emits: calc(25rem * 2) */
  margin: ${token("calc(size.400 * 2)")};

  /* Emits: -25rem */
  bottom: ${token("-size.400")};
`

2. Object Styles (Vanilla Extract, StyleX, Panda CSS, Emotion)

export const boxStyle = style({
  // Emits: rgba(var(--color-surface-rgb), 0.5)
  color: token("color.surface/50"),

  // Emits: calc(25rem * 2)
  margin: token("calc(size.400 * 2)"),

  // Emits: -25rem
  bottom: token("-size.400"),
})

3. Inline React Styling

export const Box = () => (
  <div
    style={{
      // Emits: rgba(var(--color-brand-rgb), 0.5)
      color: token("color.brand/50"),
    }}
  >
    Safely typed static inline styles!
  </div>
)

Grammar Style validates any token strings natively at compile time enforcing literal string compliance instantly!

// Typos in root primitives or paths are caught instantly with suggestions
/* Error: invalid token: 'sz.12' Did you mean 'size.12'? */
const p = token("sz.12")

// Trying to access mapped variables that don't exist in your semantics
/* Error: invalid token: 'color.foo' */
const bg = token("color.foo")

// Breaking geometric scaling constraints unless `options.useStrictSizes` was set to false
/* Error: invalid token: 'size.15' */
const width = token("size.15")

⬆️ Back to Top

📐 Media Queries: media & breakpoint

In addition to token(), grammar-style natively exposes a media object directly from the root package. It is a Proxy that lazily inspects your grammar.config breakpoints and automatically evaluates them into properly formatted, reusable @media query strings.

⚠️ Strict Sandbox Warning (Linaria, Vanilla Extract, Next.js): If your styling framework restricts Node built-ins (fs, jiti) during compilation, importing media directly will throw a Sandbox Error. To fix this, run npx grammar-style generate (or add it to your package.json dev script) to dump a statically readable token cache!

1. Template Strings (Linaria, Styled Components)

import { media, token } from "grammar-style"

export const Footer = styled.footer`
  /* Emits correctly formatted native `@media` block! */
  ${media.lg} {
    padding: ${token("size.16")};
  }
`

2. Object Syntax (Vanilla Extract, StyleX, Emotion)

For CSS-in-JS libraries that use object syntax and expect raw condition strings (like Vanilla Extract or StyleX) instead of full @media wrappers, we also export a native breakpoint object.

import { breakpoint, token } from "grammar-style"

export const boxStyle = style({
  "@media": {
    /* Emits strictly the condition block: `(min-width: 62.5rem)` */
    [breakpoint.lg]: {
      padding: token("size.32"),
    },
  },
})

Want to see full architecture breakdowns? Check out the Media Queries Documentation for full implementation guides spanning Vanilla Extract, StyleX, Emotion, Linaria, and more alongside deep dives into Client-Side restrictions and explicit lazy-caching rules!

⬆️ Back to Top

⚙️ Adapters

grammar-style is framework-agnostic. We don't care what compiler you use to handle your resulting string literals. We offer out-of-the-box Adapters to inject your grammar.config.ts into multiple major styling frameworks seamlessly.

Why adapters? Most styling tools (like Tailwind, Panda, Linaria, StyleX) require tokens to be formatted and nested into their specific compiler shape. Instead of rewriting your tokens four times for four different compilers over the lifetime of a project, build your dictionary heavily once in defineGrammar and export it into your runtime compiler framework instantly.

Available natively out-of-the-box:

Just drop the adapter directly into your framework's provider or config plugin layer and move on to building your application!

🔒 Strict Sandbox Mode (Optional)

If your framework evaluates code in a strictly isolated AST sandbox (like Linaria or Vanilla-Extract inside Next.js/Vite) that bans Node.js disk reading, you can optionally pass your config object explicitly into any adapter to completely bypass dynamic disk reads!

import config from "../../grammar.config.ts"
const grammar = createLinariaTheme(config)

Example 1: Tailwind CSS

Drop grammar-style natively into your tailwind.config.ts configuration to seamlessly map all semantic variables and base primitives into standard Tailwind utility classes (e.g., text-primary, mt-brand, rounded-soft).

// tailwind.config.ts
import createTailwindTheme from "grammar-style/tailwind"

// grammar-style automatically reads your local grammar.config.ts!
const grammar = createTailwindTheme()

export default {
  content: ["./src/**/*.{js,ts,jsx,tsx}"],
  theme: grammar.theme,
}

Example 2: Panda CSS

Consume natively transformed objects safely into Panda's strict static definitions mapping. Because Panda compiles natively at build-time, you securely extend your panda.config.ts effortlessly!

// panda.config.ts
import { defineConfig } from "@pandacss/dev"
import createPandaTheme from "grammar-style/panda"

const grammar = createPandaTheme()

export default defineConfig({
  // ...
  theme: {
    extend: {
      tokens: grammar.panda.primitives,
      semanticTokens: grammar.panda.semantics,
    },
  },
})

Using something else? Check out the Adapters Documentation for full implementation guides spanning Styled Components, Vanilla Extract, StyleX, Emotion, and Linaria!

⬆️ Back to Top

🏗️ Building Strict Custom Utilities

Since defining an entire internal design system is inherently contextual, you'll likely want to create custom opinionated abstractions (like complex shadows or layout builders). Grammar Style natively exports a powerful generic types module making it mathematically proven to secure custom utilities:

import { token, type TokenPath } from "grammar-style"

// Dynamically extracts autocomplete strictly explicitly targeting colors!
const border = (
  color: TokenPath<"color">,
  placement: "top" | "bottom" | "all" = "all",
): string => {
  if (placement === "top") {
    return `inset 0 ${token("size.1")} 0 ${token(color)}`
  }
  if (placement === "bottom") {
    return `inset 0 ${token("-size.1")} 0 ${token(color)}`
  }
  return `inset 0 0 0 ${token("size.1")} ${token(color)}`
}

// Strictly Typed ✅
border("color.danger.400", "top")

// Type Error: Argument of type '"size.4"' is not assignable to "color.*" ❌
border("size.4", "bottom")