Components are composed by calling them inside another component’s body. When you writeDocumentation Index
Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
Use this file to discover all available pages before exploring further.
Text(...), VStack(...), or MyCustomCard(...), the runtime looks the name up in a name-to-implementation map and returns a builder that participates in the AST. That same lookup is what lets a layout component reference view components it allows, lets a component recurse into itself, and lets the host swap an implementation for a custom one.
This page explains how the lookup works, the patterns you use to compose components, and how to declare slots that accept child components.
Calling other components
The most common form of composition is direct usage: a component’s body calls other components by name and arranges them with stacks and modifiers.- Built-in components are always available. Every name in the BindJS type definitions —
VStack,HStack,Text,Image,Button, and the rest — is registered before any component code runs. - The host registers additional names. Custom components are added to the lookup before the body executes. In Metabind, this happens automatically through the published package; the components in your project are registered against the active package set when the runtime starts.
- Unknown names render as a placeholder. Calling an unregistered name does not crash the runtime. It renders a placeholder and surfaces a diagnostic to the host, so a missing dependency is visible without taking the surrounding tree down.
Self-reference
UseSelf({...}) inside a component’s body to render the component recursively with different props. Self’s prop types are inferred from the component’s own properties schema, so the call is type-checked against the same shape the body already receives.
A recursive list is the canonical case — items at the top level can have nested children, and the same component renders both levels:
Self only references the current component. To recurse through a different component, call that component by name.
Environment-based conditional rendering
A component can adapt its output to the surrounding environment. Read the environment withuseEnvironment() and branch on values that ancestor components or the host has set:
.environment(key, value) and is visible only inside that ancestor’s subtree — see State and environment for how values flow and the keys a runtime injects.
Slots of child components
A layout component declares where children can be placed by combiningPropertyComponent (a single slot) or PropertyArray of PropertyComponent (a list slot) with the allowedComponents option. The names you choose for the slots become the prop names the body reads — the schema, the editor inspector, and the AI tool call all use the same vocabulary.
There are three patterns. Pick the one that matches the layout’s structure.
Single section
When the layout has one content area, usecomponents as the slot name. This is the convention editors expect for the default content slot:
inspector: { visible: false } hides the slot from the form-style inspector — the slot is configured by dropping components into the visual canvas, not by editing a list field.
Multiple sections
When the layout has more than one content area, declare each as its own slot with its ownallowedComponents list and, where appropriate, validation rules:
maxItems and minItems apply to the list at the schema level, so an LLM that generates input against the tool’s schema sees the same constraints the editor enforces.
Domain-specific naming
When the slot represents a specific kind of content, name it for what it holds. The slot name shows up in the inspector and in the schema the AI sees, so a domain name reads better than a generic one:ingredients: PropertyArray({ valueType: PropertyComponent({ allowedComponents: ["Ingredient"] }) }) produces a much sharper schema than a generic components slot would — the AI sees exactly what kind of child belongs there.
Single-component slots
For a slot that holds one component instead of a list, drop thePropertyArray wrapper and use PropertyComponent directly:
props.header as a single component. Use this for chrome that is structurally singular — a header, a hero, a CTA — rather than for repeating content.
allowedComponents is the boundary the runtime governs. A slot that lists ["FAQItem"] will not accept anything else, even if the AI returns a different component shape. The same allowlist drives schema generation, so what the LLM is allowed to choose matches what the renderer is allowed to render.What to read next
Components and bodies
The shape of a
defineComponent call and how the body executes.Properties
Every property helper, including
PropertyComponent and PropertyArray.State and environment
How
useState, useStore, and useEnvironment move data through the tree.Schema generation
How
properties and allowedComponents flow into the AI-visible tool schema.