Skip to content
Back to skills

Catalog

ASecurity

System for letting an LLM render custom React components by emitting fenced code blocks with JSON specs. The catalog ships a remark plugin, a `<pre>` override, and a system-prompt generator — all wired through `<Chat components={catalog} />`.

  • 4 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added May 27, 2026
data-aigoreactnode

Works with

  • cli

Security analysis

A100/100

Scanned May 27, 2026

npx -y skills add reaviz/skills --skill catalog --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Catalog?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Catalog
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/reaviz-catalog/badge)](https://www.skillsdirectory.com/skills/reaviz-catalog)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# ComponentCatalog

System for letting an LLM render custom React components by emitting fenced code blocks with JSON specs. The catalog ships a remark plugin, a `<pre>` override, and a system-prompt generator — all wired through `<Chat components={catalog} />`.

## Imports

```tsx
import {
  componentCatalog,
  ComponentRenderer,
  ComponentError,
  createComponentPre,
  createChartComponentDef,
  validateSpec,
  generatePrompt,
  type ComponentCatalog,
  type ComponentDefinition,
  type ComponentDefinitions,
  type ComponentSpec,
  type ComponentCatalogOptions,
  type ComponentCatalogError,
  type ComponentErrorProps
} from 'reachat';
import { z } from 'zod';
```

## componentCatalog()

Main factory. Takes a map of component definitions and returns a catalog object ready for `<Chat>`.

```ts
function componentCatalog(
  definitions: ComponentDefinitions,
  options?: ComponentCatalogOptions
): ComponentCatalog;

interface ComponentCatalogOptions {
  /** Fenced-code language tag (default: 'component') */
  language?: string;
  /** Custom error renderer — return ReactNode or undefined for default */
  onError?: (error: ComponentCatalogError) => ReactNode | undefined;
}

interface ComponentCatalog {
  remarkPlugin: Plugin;       // Pass-through plugin (rendering happens in <pre>)
  components: Components;     // { pre: ComponentPre } for react-markdown
  systemPrompt: () => string; // LLM instructions
  definitions: ComponentDefinitions;
}
```

`Chat` accepts a catalog directly via the `components` prop and wires everything in:

```tsx
<Chat sessions={sessions} components={catalog}>...</Chat>
```

For advanced control, splice the pieces yourself:

```tsx
<Chat
  sessions={sessions}
  remarkPlugins={[remarkGfm, catalog.remarkPlugin]}
  markdownComponents={{ ...catalog.components, pre: MyCustomPre }}
>...</Chat>
```

## ComponentDefinition

```ts
interface ComponentDefinition<TProps = Record<string, any>> {
  description: string;        // Used by systemPrompt
  props: z.ZodType<TProps>;   // Runtime validation + prompt schema
  component: FC<TProps & {
    children?: ReactNode;
    sendMessage?: (message: string) => void;
  }>;
}

type ComponentDefinitions = Record<string, ComponentDefinition>;
```

The `component` receives validated props plus:
- `children` — rendered nested specs
- `sendMessage` — pulled from `ChatContext` so the rendered UI can dispatch a follow-up message

## Quick example

```tsx
const catalog = componentCatalog({
  WeatherCard: {
    description: 'Displays weather for a city',
    props: z.object({
      city: z.string().describe('City name'),
      temperature: z.number().describe('Temp in Fahrenheit')
    }),
    component: ({ city, temperature, sendMessage }) => (
      <div className="rounded-xl border p-4">
        <h3>{city}</h3>
        <p>{temperature}°F</p>
        <button onClick={() => sendMessage?.(`Tell me more about ${city}`)}>
          Tell me more
        </button>
      </div>
    )
  }
});

<Chat sessions={sessions} components={catalog}>
  <SessionMessages />
  <ChatInput />
</Chat>
```

The LLM emits:

````markdown
```component
{ "type": "WeatherCard", "props": { "city": "SF", "temperature": 68 } }
```
````

## JSON spec format

```ts
interface ComponentSpec {
  type: string;                     // Must match a key in the catalog
  props: Record<string, any>;       // Validated against the Zod schema
  children?: ComponentSpec[];       // Optional nested specs
}
```

- **Single**: `{ "type": "Card", "props": {...} }`
- **Array**: `[ {...}, {...} ]` — multiple top-level components in one block
- **Nested**: `{ "type": "Row", "props": {}, "children": [ {...}, {...} ] }`

## Errors

Validation produces `ComponentCatalogError` with one of four `type`s:

| type | When |
|------|------|
| `invalid_json` | The fenced block is not valid JSON |
| `unknown_component` | `spec.type` is not in the catalog |
| `invalid_props` | Zod validation failed (issues passed through) |
| `render_error` | The component threw during render |

Each component is wrapped in a React error boundary so a single failure doesn't break the markdown stream. Provide a custom UI via `options.onError`:

```tsx
componentCatalog(defs, {
  onError: error =>
    error.type === 'invalid_props' ? (
      <pre>{JSON.stringify(error.issues, null, 2)}</pre>
    ) : undefined
});
```

## systemPrompt()

Generates LLM instructions describing the available components, their descriptions, and Zod-derived prop schemas. Useful as a system message when calling your model.

```ts
const prompt: string = catalog.systemPrompt();
```

## createChartComponentDef()

Pre-built definition that wraps `ChartRenderer`, allowing the LLM to render charts.

```tsx
import { componentCatalog, createChartComponentDef } from 'reachat';

const catalog = componentCatalog({
  Chart: createChartComponentDef()
});
```

LLM output:

````markdown
```component
{
  "type": "Chart",
  "props": {
    "type": "bar",
    "title": "Active users",
    "data": [{ "key": "Mon", "data": 12 }, { "key": "Tue", "data": 18 }]
  }
}
```
````

Supported `type`s: `bar`, `line`, `area`, `pie`, `radialBar`, `radialArea`, `sparkline`. Requires `reaviz` as a peer dependency.

## Lower-level helpers

- **`createComponentPre(definitions, options?)`** — returns the `<pre>` override component used in `catalog.components` (for advanced custom wiring)
- **`ComponentRenderer`** — renders a `ComponentSpec` directly (for custom dispatch outside of markdown)
- **`validateSpec(spec, definitions)`** — runs the four-step validation pipeline (JSON parse, type lookup, Zod, children)
- **`generatePrompt(definitions, language?)`** — bare prompt generator (catalog wraps this)
- **`ComponentError`** — default error UI; props in `ComponentErrorProps`

## Dependencies

- `zod` — required, used for runtime prop validation
- `reaviz` — peer-optional, only needed for `createChartComponentDef()`

## Theme key

```
theme.component.base
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.