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
| Name | Description | Type | Default |
|---|---|---|---|
namerequired | kebab-case, unique within the registry that hosts it. | string | — |
typerequired | A 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' | — |
titlerequired | Short human name, shown in a picker. | string | — |
descriptionrequired | One sentence on what it is for. | string | — |
author | Whoever publishes it. | string | — |
ngwr | Compatible ngwr versions, as a semver range — e.g. ">=11". | string | — |
dependencies | npm packages beyond ngwr and its peers. | string[] | [] |
registryDependencies | Absolute https URLs of other items this one composes. Relative is meaningless — the resolving tool does not know where this item came from. | string[] | [] |
entryPoints | The ngwr/* subpaths the item imports from. Checked against the real catalog, so a typo fails instead of installing something that will not compile. | string[] | [] |
cssVars | Token overrides per theme (light / dark). Every key must be a --wr-* token. | { light?: Record<string, string>; dark?: Record<string, string> } | — |
files | Source 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.