diff --git a/apps/v4/content/docs/registry/api-reference.mdx b/apps/v4/content/docs/registry/api-reference.mdx new file mode 100644 index 0000000000..09ff0fb18d --- /dev/null +++ b/apps/v4/content/docs/registry/api-reference.mdx @@ -0,0 +1,422 @@ +--- +title: API Reference +description: Programmatic API for working with registries, schemas and presets. +--- + +The `shadcn` package exposes a set of programmatic APIs in addition to the CLI. +You can use these to fetch and resolve registry items, validate registry JSON, +and build custom tooling on top of the registry. + +Each API is available under a dedicated subpath import. + +```ts +import { getRegistryItems } from "shadcn/registry" +import { registryItemSchema } from "shadcn/schema" +``` + + + The CLI commands themselves are not part of the public API. Only the imports + documented below are considered stable. + + +## shadcn/registry + +Fetch and resolve items from configured registries. + +Most functions accept an options object. The two options below are common to all +of them. In the examples that follow, `config` refers to this optional value — +omit it to use the built-in registries. + +### config + +- **Type:** `Partial` +- **Default:** built-in registries only + +The resolved contents of your `components.json` file. Its `registries` field +maps a namespace (e.g. `@acme`) to a URL and any authentication headers or +environment variables required to reach it. + +```ts showLineNumbers +import { getRegistryItems } from "shadcn/registry" + +const items = await getRegistryItems(["@acme/login-form"], { + config: { + registries: { + "@acme": "https://acme.com/r/{name}.json", + }, + }, +}) +``` + +### useCache + +- **Type:** `boolean` +- **Default:** `true` + +Registry responses are cached **in memory for the lifetime of the process**, +keyed by the resolved URL. Because the in-flight promise is cached, concurrent +requests for the same URL are de-duplicated into a single fetch. + +Leave this enabled for one-off scripts and CLI runs. Set it to `false` in +long-running processes (servers, watchers, the MCP server) where the registry +can change between requests and you need fresh data each time. + +```ts +const fresh = await getRegistry("@shadcn", { useCache: false }) +``` + +### getRegistry + +Fetch a single registry by name. + +```ts showLineNumbers +import { getRegistry } from "shadcn/registry" + +const registry = await getRegistry("@acme", { + config, // optional Partial + useCache: true, +}) +``` + +### getRegistryItems + +Fetch one or more registry items by their qualified names. + +```ts showLineNumbers +import { getRegistryItems } from "shadcn/registry" + +const items = await getRegistryItems(["@acme/button", "@acme/card"], { + config, + useCache: true, +}) +``` + +Returns an array of registry items: + +```json showLineNumbers +[ + { + "name": "button", + "type": "registry:ui", + "dependencies": ["@radix-ui/react-slot"], + "files": [ + { + "path": "ui/button.tsx", + "type": "registry:ui", + "content": "..." + } + ] + } +] +``` + +### resolveRegistryItems + +Resolve multiple items together with their registry dependencies, merged into a +single tree. Unlike [`getRegistryItems`](#getregistryitems), which returns the +items as a list, this walks each item's `registryDependencies` and flattens +everything — files, dependencies, CSS variables — into one installable object. + +```ts showLineNumbers +import { resolveRegistryItems } from "shadcn/registry" + +const tree = await resolveRegistryItems( + ["@acme/button", "@acme/card", "@acme/dialog"], + { config } +) +``` + +Returns a single merged tree: + +```json showLineNumbers +{ + "dependencies": ["@radix-ui/react-slot", "@radix-ui/react-dialog"], + "files": [ + { "path": "ui/button.tsx", "type": "registry:ui", "content": "..." }, + { "path": "ui/card.tsx", "type": "registry:ui", "content": "..." }, + { "path": "ui/dialog.tsx", "type": "registry:ui", "content": "..." } + ], + "cssVars": { + "theme": { + "font-heading": "Poppins, sans-serif" + }, + "light": { + "brand": "oklch(0.205 0.015 18)" + }, + "dark": { + "brand": "oklch(0.205 0.015 18)" + } + }, + "docs": "" +} +``` + +### getRegistries + +Fetch the registry directory. + +```ts showLineNumbers +import { getRegistries } from "shadcn/registry" + +const registries = await getRegistries({ useCache: true }) +``` + +Returns an array of registry entries: + +```json +[ + { + "name": "@shadcn", + "url": "https://ui.shadcn.com/r/{name}.json", + "homepage": "https://ui.shadcn.com" + } +] +``` + +### searchRegistries + +Search across one or more registries with fuzzy matching. + +```ts showLineNumbers +import { searchRegistries } from "shadcn/registry" + +const results = await searchRegistries(["@shadcn"], { + query: "button", + types: ["registry:component"], + limit: 100, + offset: 0, + config, + continueOnError: true, // skip (don't throw on) registries that fail to load +}) +``` + +Returns matching items wrapped in pagination metadata: + +```json +{ + "pagination": { "total": 1, "offset": 0, "limit": 100, "hasMore": false }, + "items": [ + { + "name": "button", + "type": "registry:ui", + "description": "A button component.", + "registry": "@shadcn", + "addCommandArgument": "@shadcn/button" + } + ] +} +``` + +### loadRegistry + +Read and resolve a local `registry.json` file from disk, following any +`include` references, and return the registry catalog. + +```ts showLineNumbers +import { loadRegistry } from "shadcn/registry" + +const catalog = await loadRegistry({ + cwd: process.cwd(), // defaults to process.cwd() + registryFile: "registry.json", // defaults to "registry.json" +}) +``` + +The returned catalog lists every item but **omits file contents** — like a +built `registry.json` index. + + + [`getRegistry`](#getregistry) fetches a **remote** registry over the network + (by namespace, URL or GitHub address) and expects the served catalog to + already be flattened — it rejects catalogs that still use `include`. + `loadRegistry` reads a **local** `registry.json` from disk and resolves + `include` references itself. + + +### loadRegistryItem + +Read a single item from a local `registry.json` by name, with its file contents +read from disk and inlined. + +```ts showLineNumbers +import { loadRegistryItem } from "shadcn/registry" + +const item = await loadRegistryItem("login-form", { cwd: process.cwd() }) +``` + +Returns a fully resolved registry item with file contents: + +```json +{ + "$schema": "https://ui.shadcn.com/schema/registry-item.json", + "name": "login-form", + "type": "registry:component", + "files": [ + { + "path": "registry/new-york/login-form.tsx", + "type": "registry:component", + "content": "..." + } + ] +} +``` + + + [`getRegistryItems`](#getregistryitems) resolves items from a **remote** + registry over the network. `loadRegistryItem` builds a single item on demand + from your **local** source files, reading each file from disk. Use it in a + dynamic route that serves `registry-item.json` responses. + + +### Errors + +All registry functions throw typed errors that extend `RegistryError`. Use the +`RegistryErrorCode` enum or `instanceof` checks to handle them. + +```ts showLineNumbers +import { RegistryError, RegistryNotFoundError } from "shadcn/registry" + +try { + await getRegistry("@unknown") +} catch (error) { + if (error instanceof RegistryNotFoundError) { + // handle missing registry + } +} +``` + +Available error classes: + +- `RegistryError` +- `RegistryNotFoundError` +- `RegistryUnauthorizedError` +- `RegistryForbiddenError` +- `RegistryFetchError` +- `RegistryNotConfiguredError` +- `RegistryLocalFileError` +- `RegistryParseError` +- `RegistryValidationError` +- `RegistryItemNotFoundError` +- `RegistriesIndexParseError` +- `RegistryMissingEnvironmentVariablesError` +- `RegistryInvalidNamespaceError` + +## shadcn/schema + +The Zod schemas used to validate `registry.json`, `registry-item.json` and +`components.json`. Useful for validating registry data in your own tooling. + +```ts +import { registryItemSchema, registrySchema } from "shadcn/schema" + +const result = registryItemSchema.safeParse(json) +if (!result.success) { + console.error(result.error) +} +``` + +Key schemas: + +- `registrySchema` +- `registryItemSchema` +- `registryItemFileSchema` +- `registryItemTypeSchema` +- `registryItemCssVarsSchema` +- `registryItemTailwindSchema` +- `registryBaseColorSchema` +- `configSchema` +- `presetSchema` + +Inferred types are exported alongside them: + +- `Registry` +- `RegistryItem` +- `RegistryBaseItem` +- `RegistryFontItem` +- `Preset` +- `ConfigJson` + +## shadcn/preset + +Encode, decode and validate theme presets, plus the preset option constants used +by the theme editor. + +### encodePreset + +Encode a `Partial` into a short, URL-safe preset code. Any fields +you omit fall back to `DEFAULT_PRESET_CONFIG`. + +```ts showLineNumbers +import { encodePreset } from "shadcn/preset" + +const code = encodePreset({ + style: "vega", + baseColor: "stone", + theme: "blue", + radius: "large", + font: "geist", +}) +``` + +Returns a version-prefixed string: + +```ts showLineNumbers +"bJ4FLU0" +``` + +### decodePreset + +Decode a preset code back into a full `PresetConfig`. Returns `null` if the code +is missing or invalid. + +```ts showLineNumbers +import { decodePreset } from "shadcn/preset" + +const config = decodePreset("bJ4FLU0") +``` + +Returns the resolved config (omitted fields are filled with their defaults): + +```json +{ + "style": "vega", + "baseColor": "stone", + "theme": "blue", + "chartColor": "neutral", + "iconLibrary": "lucide", + "font": "geist", + "fontHeading": "inherit", + "radius": "large", + "menuAccent": "subtle", + "menuColor": "default" +} +``` + +```ts +decodePreset("not-a-code") // null +``` + +### Other exports + +Additional functions for validating codes and generating random presets: + +- `isPresetCode` +- `isValidPreset` +- `generateRandomConfig` +- `generateRandomPreset` +- `toBase62` +- `fromBase62` + +Constants: + +- `PRESET_BASES` +- `PRESET_STYLES` +- `PRESET_BASE_COLORS` +- `PRESET_THEMES` +- `PRESET_ICON_LIBRARIES` +- `PRESET_FONTS` +- `PRESET_FONT_HEADINGS` +- `PRESET_RADII` +- `PRESET_MENU_ACCENTS` +- `PRESET_MENU_COLORS` +- `PRESET_CHART_COLORS` +- `DEFAULT_PRESET_CONFIG` diff --git a/apps/v4/content/docs/registry/meta.json b/apps/v4/content/docs/registry/meta.json index b82573fdc8..61a2cac965 100644 --- a/apps/v4/content/docs/registry/meta.json +++ b/apps/v4/content/docs/registry/meta.json @@ -10,6 +10,7 @@ "authentication", "mcp", "open-in-v0", + "api-reference", "registry-json", "registry-item-json" ]