Registry

An open JSON format for shareable theme presets and blocks — one file anyone can host, any tool can fetch, and a schema that says what is valid.

What it is

A registry item is one installable unit as a single JSON file: a theme preset (token overrides), a block (several ngwr components composed into a page or a section), or a component. There is no server and no account — an item is a URL. Host it on your own domain, in a gist, in your repo; a tool fetches it, validates it against the schema, and writes what it describes.

The format is published at ngwr.dev/registry/schema.json, and the two worked examples are beside it — theme-slate.json and block-sign-in.json. Point your editor's $schema at the first and you get completion and validation while you write one.

The shape borrows from shadcn's registry on purpose: an author who has published one of those should recognise this one. What differs is what Angular needs — entryPoints names ngwr/* subpaths, and cssVars names --wr-* tokens rather than arbitrary properties.

A theme preset

Tokens, and nothing else.

{
  "$schema": "https://ngwr.dev/registry/schema.json",
  "name": "theme-slate",
  "type": "registry:theme",
  "title": "Slate",
  "description": "A cooler, lower-saturation take on the default palette.",
  "ngwr": ">=11",
  "cssVars": {
    "light": {
      "--wr-color-primary": "#41598f",
      "--wr-color-primary-rgb": "65, 89, 143",
      "--wr-color-surface": "#fbfcfd"
    },
    "dark": {
      "--wr-color-primary": "#5b7fd6",
      "--wr-color-primary-rgb": "91, 127, 214",
      "--wr-color-surface": "#0c1018"
    }
  }
}

Keys must be --wr-*. A preset that sets --brand-blue is arbitrary CSS wearing the label: people install a theme expecting the library's own token layer to be what changes, and everything ngwr paints is derived from that layer. See tokens for what is available.

A block

Files a tool writes into your project.

{
  "$schema": "https://ngwr.dev/registry/schema.json",
  "name": "block-sign-in",
  "type": "registry:block",
  "title": "Sign-in card",
  "description": "A centred sign-in card wired to Signal Forms.",
  "ngwr": ">=11",
  "entryPoints": ["ngwr/card", "ngwr/form", "ngwr/input", "ngwr/button", "ngwr/validators"],
  "files": [
    {
      "path": "sign-in.ts",
      "target": "src/app/sign-in/sign-in.ts",
      "content": "import { Component } from '@angular/core';\n…"
    }
  ]
}

The fields

NameDescriptionTypeDefault
namerequiredkebab-case, unique within the registry that hosts it.string
typerequiredA theme is tokens and nothing else. A block composes several ngwr components into a page or a section. A component is one unit of UI.'registry:theme' | 'registry:block' | 'registry:component'
titlerequiredShort human name, shown in a picker.string
descriptionrequiredOne sentence on what it is for.string
authorWhoever publishes it.string
ngwrCompatible ngwr versions, as a semver range — e.g. ">=11".string
dependenciesnpm packages beyond ngwr and its peers.string[][]
registryDependenciesAbsolute https URLs of other items this one composes. Relative is meaningless — the resolving tool does not know where this item came from.string[][]
entryPointsThe ngwr/* subpaths the item imports from. Checked against the real catalog, so a typo fails instead of installing something that will not compile.string[][]
cssVarsToken overrides per theme (light / dark). Every key must be a --wr-* token.{ light?: Record<string, string>; dark?: Record<string, string> }
filesSource files to write: path (inside the item), target (relative to the project root) and content. Required for a block or a component, refused for a theme.RegistryFile[][]

Two rules worth knowing before you publish one

A target is a relative path, and that is enforced. An item is remote content that a CLI writes to disk, so files[].target rejects absolute paths, Windows drive letters, anything that looks like a URL scheme, and any .. segment — including one that appears after a legitimate prefix, which is the form a naive "does it start with .." check misses. If your item needs to write outside the project, it is not a registry item.

A theme has no files and a block has at least one. A theme that ships code would install unreviewed source as part of "changing the colours"; a block that ships none installs nothing at all. Both are refused rather than warned about.

pnpm check:registry runs in this repo's lint chain: it validates every shipped item, checks each entryPoints name against the real catalog, and compares the published schema against the validator so the contract and the enforcement cannot drift apart.

See also