LLM-first developer tool for generating Component Catalogues
The fastest way to create a new component:
catalogue new <component-id> [options]
| Option | Description |
|---|---|
-t, --title <title> |
Human-readable title |
-s, --status <status> |
stable, beta, or deprecated |
-k, --kind <kind> |
standalone, subcomponent, or feature |
# Basic component
catalogue new user-card
# With options
catalogue new data-table --title "Data Table" --status stable
# Subcomponent
catalogue new table-row --kind subcomponent
This creates:
registry/components/user-card/
├── component.json
├── docs.md
└── scenarios/
└── default.json
src/components/
└── user-card.ts
mkdir -p registry/components/my-button/scenarios
{
"id": "my-button",
"title": "My Button",
"status": "stable",
"kind": "standalone",
"description": "A customizable button component",
"tags": ["form", "action", "interactive"],
"exports": {
"customElement": "my-button"
},
"playground": {
"primaryScenarioId": "my-button-default",
"controls": {
"variant": {
"type": "select",
"label": "Variant",
"defaultValue": "primary",
"options": ["primary", "secondary", "danger"]
},
"size": {
"type": "select",
"label": "Size",
"options": ["small", "medium", "large"]
},
"disabled": {
"type": "boolean",
"label": "Disabled"
}
}
}
}
Create scenarios/default.json:
{
"id": "my-button-default",
"title": "Default",
"description": "Default button state",
"componentId": "my-button",
"primary": true,
"render": {
"element": "my-button",
"attrs": {
"variant": "primary",
"size": "medium"
},
"slots": {
"default": "Click me"
}
}
}
Create docs.md:
# My Button
A customizable button component for user interactions.
## Usage
\`\`\`html
<my-button variant="primary">Click me</my-button>
\`\`\`
## Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| variant | string | primary | Visual style |
| size | string | medium | Button size |
| disabled | boolean | false | Disabled state |
Create src/components/my-button.ts:
export class MyButton extends HTMLElement {
static get observedAttributes() {
return ['variant', 'size', 'disabled'];
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
}
attributeChangedCallback() {
this.render();
}
private render() {
const variant = this.getAttribute('variant') || 'primary';
const size = this.getAttribute('size') || 'medium';
const disabled = this.hasAttribute('disabled');
this.shadowRoot!.innerHTML = `
<style>
/* Your styles here */
</style>
<button class="${variant} ${size}" ${disabled ? 'disabled' : ''}>
<slot></slot>
</button>
`;
}
}
customElements.define('my-button', MyButton);
Add to src/components/index.ts:
export * from './my-button.js';
catalogue validate
| Field | Type | Description |
|---|---|---|
id |
string | Unique kebab-case identifier |
title |
string | Human-readable name |
status |
string | stable, beta, or deprecated |
kind |
string | standalone, subcomponent, or feature |
exports.customElement |
string | Custom element tag name |
playground.primaryScenarioId |
string | Default scenario ID |
playground.controls |
object | Control definitions |
| Field | Type | Description |
|---|---|---|
description |
string | Brief description |
tags |
string[] | Searchable tags |
parentId |
string | Parent component (for subcomponents) |
subcomponents |
string[] | List of subcomponent IDs |
exports.package |
string | npm package name |
exports.entry |
string | Entry point path |