defineComponent() with three required fields — a name, a props schema, and a render function — and Solar turns that config into a callable, self-validating component function. This explicit structure is what lets Solar validate props at runtime, power the component registry, and give AI agents a reliable catalog to reason about before writing any composition code.
Anatomy of a component
The example below shows a completeButton component. It covers everything you need to write a production-ready Solar component: typed and validated props, a default value, an enum constraint, and registration with the registry.
Button(...) is called. If a prop fails validation, you get a structured ContractError immediately — before render ever runs.
The config object
defineComponent() takes a single config object with three keys.
name (required string)
The component’s display name. Solar uses this in error messages, the component registry, and the _source tag it stamps on every vnode the component returns. It must exactly match the filename and the default export name.
props (object)
A map of prop names to schema descriptors. Each descriptor controls the type check, required constraint, default value, and allowed enum values for that prop. See the Contracts page for the full list of descriptor fields.
render (required function)
Receives the fully resolved and validated props object, then returns a vnode built with createElement(). Solar calls render only after all props have passed validation, so you can rely on the types inside this function.
File structure rules
Solar enforces a rigid set of file conventions. These rules exist so that AI agents can navigate and generate component files without needing to infer structure from context.One component per file
Each
.js file in the components/ directory defines exactly one component. Never export multiple components from a single file.Filename matches the component name
If your component’s
name is "UserCard", the file must be UserCard.js. The registry, the slot validator, and the error formatter all depend on this 1:1 mapping.Default export is the defineComponent call
Assign the result of
defineComponent() to a const, then export default that const. Do not export the raw config object or a wrapper function.createElement
Insiderender, you build your vnode tree with createElement(type, props, ...children).
type— a string tag name ('div','button','h2', etc.) or another component functionprops— an object of DOM attributes and event handlers; pass{}if you have none...children— zero or more child vnodes or strings
createElement returns a plain vnode object. Solar’s renderer walks the vnode tree and mounts it to the DOM.
Components are called as plain functions, not with JSX or a template compiler. To use your
Button component, call it directly: Button({ label: 'Save', onClick: handleSave }). The return value is a vnode you can pass as a child to createElement or as a slot prop to another component.