Skip to main content
The Solar registry is a central catalog of every component in your application. Components register themselves at import time, and the registry immediately makes them queryable by name and inspectable by schema. This is what separates Solar from frameworks that rely on file-system conventions or import graphs alone: any caller — human or model — can ask the registry for a complete, structured description of every available component before writing a single line of composition code.

Registering a component

After you define a component with defineComponent(), call registry.register() to add it to the catalog.
import { defineComponent, registry } from './solar/index.js'

const Button = defineComponent({
  name: 'Button',
  props: {
    label:   { type: 'string',   required: true },
    onClick: { type: 'function', required: true },
    variant: { type: 'string',   enum: ['primary', 'secondary'], default: 'primary' },
  },
  render({ label, onClick, variant }) {
    return createElement('button', { class: variant, onclick: onClick }, label)
  },
})

registry.register(Button)
export default Button
If you pass anything that was not produced by defineComponent(), registry.register() throws a ContractError with a fix field telling you to wrap the function first.

Reading the manifest

registry.manifest() returns a JSON string of every registered component and its full props schema. This is the primary interface for AI agents.
registry.manifest()
[
  {
    "name": "Button",
    "props": {
      "label":   { "type": "string",   "required": true },
      "onClick": { "type": "function", "required": true },
      "variant": { "type": "string",   "enum": ["primary", "secondary"], "default": "primary" }
    }
  }
]
The manifest includes every field from the original schema descriptor — type, required, default, enum, and accepts for slot props — so a model receives complete information with no follow-up queries needed.

Registry API

registry.register(component)
void
Registers a component in the catalog. The component must be the return value of defineComponent() — it checks for an internal _isComponent flag. Throws a ContractError if you pass anything else.
registry.list()
array
Returns an array of plain objects, each with a name string and a props schema object. This is the parsed form of the manifest — useful when you want to work with the data programmatically rather than as a JSON string.
registry.manifest()
string
Returns a pretty-printed JSON string of registry.list(). Feed this directly to an AI model’s context window or system prompt so it can discover the available component catalog before generating code.
registry.get(name)
function | undefined
Returns the registered component function for the given display name, or undefined if no component with that name has been registered. Useful inside the h() compact notation parser and any dynamic composition utilities.
registry.has(name)
boolean
Returns true if a component with the given display name is registered, false otherwise. Use this to guard dynamic lookups before calling registry.get().

Why the registry matters for AI generation

Before an AI agent writes any composition code — a page layout, a form, a dashboard — it calls registry.manifest() to read the complete catalog of available components and their exact prop schemas. With that data in hand, the agent knows which components exist, what props they accept, which props are required, and what values are valid. The result is generated code that references real components with correct prop signatures, rather than hallucinated names or guessed types. This is the key architectural difference from convention-based frameworks: the registry makes the component surface area machine-readable on demand, at runtime, without a build step.

Self-registering components

The recommended pattern is to have each component file call registry.register() at the bottom, so importing the file is all you need to register the component.
// components/Button.js
import { defineComponent, createElement, registry } from '../solar/index.js'

const Button = defineComponent({ /* ... */ })

registry.register(Button)   // ← self-registers on import
export default Button
This pattern means your application code never has to explicitly register components — it just imports them.
In your main.js (or whichever file mounts your application), import every component file before calling render(). The side effect of each import runs registry.register(), so by the time your root component renders, the full catalog is available in the registry. A single import block at the top of main.js is enough.
import './components/Button.js'
import './components/Card.js'
import './components/Counter.js'
// registry is now fully populated