---
title: ComponentRegistry — Programmatic Discovery
visibility: guest
---

# ComponentRegistry — Programmatic Discovery

`Pushery\WireKit\ComponentRegistry` is the canonical PHP-side surface for
discovering every component WireKit ships. Use it when your app needs the
component catalog at runtime — generating an autocomplete list in a
search widget, validating a CMS field against shipped components, building
a custom admin tool, or feeding an AI tool the full component schema.

The registry is the single source of truth. Every CLI command (`wirekit:list`,
`wirekit:show`, `wirekit:export-json`, `wirekit:export-api-map`) is a thin
wrapper around it — the same data shape, just formatted differently.

## Quick Reference

```php
use Pushery\WireKit\ComponentRegistry;

// Every component, keyed by name.
$all = ComponentRegistry::all();
// → ['button' => ['category' => 'Display', 'description' => '...'], ...]

// Just the count.
$count = count(ComponentRegistry::all());

// Just the names.
$names = array_keys(ComponentRegistry::all());
// → ['accordion', 'action-bar', 'alert', 'alert-dialog', ...]

// One component by name.
$meta = ComponentRegistry::get('button');
// → ['category' => 'Display', 'description' => 'Action button with variants and loading state']

// Every component in one category.
$formComponents = ComponentRegistry::category('Form');
// → ['checkbox' => [...], 'combobox' => [...], 'date-picker' => [...], ...]

// Every category that has at least one component.
$categories = ComponentRegistry::categories();
// → ['Form', 'Layout', 'Typography', 'Navigation', 'Overlay', 'Display', 'System']

// Props for a single component (the @props([...]) block, parsed).
$props = ComponentRegistry::extractProps('stat');
// → [
//     ['name' => 'label', 'default' => 'null', 'default_normalized' => 'null', 'type_hint' => null, 'comment' => null],
//     ['name' => 'value', 'default' => 'null', ...],
//     ...
//   ]
```

## Methods

### `ComponentRegistry::all()`

Returns every component keyed by its slug name. Stable shape across
releases — adding a new component appends an entry; renaming requires a
major-version bump.

```php
/** @return array<string, array{category: string, description: string}> */
public static function all(): array;
```

### `ComponentRegistry::get(string $name)`

Returns the metadata for one component, or `null` when the name isn't
registered. Same shape per-entry as `all()`.

```php
/** @return array{category: string, description: string}|null */
public static function get(string $name): ?array;
```

### `ComponentRegistry::category(string $category)`

Returns every component in a category. Empty array when the category
doesn't exist.

```php
/** @return array<string, array{category: string, description: string}> */
public static function category(string $category): array;
```

### `ComponentRegistry::categories()`

Returns every unique category name across the registry. Order is
insertion-order, which matches the source-file declaration sequence.

```php
/** @return list<string> */
public static function categories(): array;
```

### `ComponentRegistry::extractProps(string $name)`

Returns the structured `@props([...])` block for a component. Routes
through `Pushery\WireKit\Support\PropsParser`, which uses PHP's own
tokenizer — no regex parsing of the prop expressions, so `config(...)`
defaults, multi-line array literals, `match(...)` expressions, and
heredoc / nowdoc values all parse cleanly.

```php
/**
 * @return list<array{
 *     name: string,
 *     default: ?string,
 *     default_normalized: ?string,
 *     type_hint: ?string,
 *     comment: ?string,
 * }>
 */
public static function extractProps(string $name): array;
```

Per-record fields:

| Field | Purpose |
|---|---|
| `name` | Prop name (string-key from the `@props` array, quote-stripped). |
| `default` | Raw default expression as it appears in source. `null` when the prop has no `=>` default clause. |
| `default_normalized` | Same expression with whitespace collapsed and comments stripped. Stable for string comparison. |
| `type_hint` | Reserved for future @phpdoc-driven augmentation. Currently always `null`. |
| `comment` | The trailing same-line `// …` comment after the prop's comma, if any. Leading `//` stripped + trimmed. |

## AI Tooling / LLM Consumption

This page is the canonical programmatic API for component discovery.
AI tools (Cursor, Claude Code, MCP servers, Aider) should prefer the PHP
surface above OR the matching CLI flags below — both are stable across
releases. **Do not parse `wirekit:show` output programmatically** — it's
optimized for human reading and isn't shape-stable.

### Machine-readable CLI surface

| Need | Use |
|---|---|
| Total component count | `php artisan wirekit:list --as=count` |
| Component name list | `php artisan wirekit:list --as=slugs` |
| Per-category count map | `php artisan wirekit:list --as=categories` |
| Full per-component metadata | `php artisan wirekit:list --as=json` |
| Single component schema (props + sub-components) | `php artisan wirekit:show <name> --as=json` |
| Full manifest with slots | `php artisan wirekit:export-json --pretty` |

All output is plain-stdout JSON with no decoration, suitable for `jq`
pipes. The schemas are stable for v2.x — additive new fields may appear,
existing field shapes won't change without a major-version bump.

## Categories

The canonical category enum across `ComponentRegistry`:

| Category | Definition | Examples |
|---|---|---|
| `Form` | Inputs and form-related controls. Carries focus/validation semantics. | `input`, `select`, `combobox`, `date-picker`, `file-upload`, `checkbox`, `toggle` |
| `Layout` | Structural primitives that compose page chrome and content regions. No conversion intent. | `app-shell`, `container`, `grid`, `stack`, `header`, `main`, `sidebar`, `footer` |
| `Typography` | Text-rendering primitives — body copy, headings, inline marks. | `heading`, `text`, `prose`, `link`, `code`, `code-block`, `blockquote`, `kbd` |
| `Navigation` | Wayfinding chrome and link surfaces. | `navbar`, `tabs`, `breadcrumb`, `sidebar`, `pagination`, `stepper`, `brand-bar` |
| `Overlay` | Layered surfaces that float above content (modal, drawer, popover, tooltip). | `modal`, `drawer`, `dropdown`, `popover`, `tooltip`, `command-palette`, `alert-dialog` |
| `Display` | Generic content presentation — cards, alerts, badges, charts. | `card`, `alert`, `badge`, `button`, `stat`, `chart`, `calendar`, `avatar` |
| `Marketing` | Components whose PRIMARY purpose is marketing / conversion. Narrow scope, clear semantic — added in v2.1.0. | `cta`, `feature`, `feature-grid`, `hero` |
| `System` | Infrastructure / glue primitives — icon resolution, font registration, structured-data emitters. | `chart`, `icon`, `fonts`, `glass`, `structured-data` |

**Usage criteria.** When deciding which category a new component belongs to, ask: *"What is the component's primary use-case?"*

- A `cta` primitive lives or dies by its conversion-funnel role → `Marketing`.
- A `reveal` animation primitive serves marketing landing pages but is also generic → `Display`.
- A `footer` is used on every page including non-marketing → `Layout`.
- A `brand-bar` is header chrome reused across marketing, app, and docs sites → `Navigation`.

The `Marketing` category was added in v2.1.0 with four canonical entries. Reserve it for components whose conversion intent is their defining trait — not every component USED on a marketing page belongs here.

Categories are stable for v2.x. Re-categorization is a `### Changed`
entry in the public CHANGELOG.

## See Also

- [Authoring Custom Components](authoring-custom-components.md) — how to
  write your own `@props([...])` blocks and have them parse cleanly.
- [Authoring Custom Alpine Plugins](authoring-custom-alpine-plugins.md) —
  defensive-cleanup pattern for plugins that drive your components.
- [CLI Reference](../cli-reference.md) — the full command surface.
