In this tutorial you’ll build a small BindJS component from scratch — a configurable call-to-action card with a title, a color variant, a counter that increments on tap, and previews for the component gallery. By the end you’ll have touched every piece of a working component: metadata, properties, a body that returns a layout, state viaDocumentation Index
Fetch the complete documentation index at: https://docs.metabind.ai/llms.txt
Use this file to discover all available pages before exploring further.
useState, and Self previews.
The component you build here renders as React on the web, SwiftUI on iOS, and Jetpack Compose on Android from this single source. You don’t write a separate version per platform.
Prerequisites
Before you start, you need:- A Metabind project with access to MCP App Studio. If you haven’t created one yet, start with Your first MCP App, then come back here.
- Familiarity with TypeScript or modern JavaScript. You don’t need React or SwiftUI experience.
Build the component
Define metadata
Every component begins with metadata that describes how it’s surfaced in the studio’s component picker, in the gallery, and in any preview UI. The fields are short and human-readable.
title is the name shown in the picker. description helps teammates understand what the component does. category groups the component alongside others — pick a name that fits your project’s organization (for example, "Cards", "Controls", "Layout").Define properties
Properties make a component configurable. Each property is declared with a helper function — A few things to notice.
PropertyString, PropertyEnum, PropertyNumber, PropertyBoolean, and so on — and the schema you build does three things at once: it generates typed props for the body, it validates inputs at runtime, and it tells the studio which inspector control to render.For the action card, you need a title and a color variant.required: true on title means the component won’t render without one. defaultValue makes the property safe to omit. options on PropertyEnum is a list of { value, label } pairs — the value is what your body receives; the label is what the inspector shows. The inspector.control: "segmented" hint asks the studio to render a segmented control instead of a dropdown.Write the body function
The body is a function that receives The flow reads top to bottom: build a
props and children and returns a component tree. You compose the tree from BindJS primitives (VStack, HStack, Text, Button, shapes) and apply modifiers like .padding(), .background(), and .cornerRadius() by chaining methods.Start with a simple layout — a vertical stack containing the title, on a colored background.VStack of two Text views, then apply padding, an expanded frame, a background color tied to the variant, and a corner radius — all by chaining modifiers off the stack itself.Add interactivity with useState
Hooks let a component hold local state across renders.
useState is the basic one, mirroring its React counterpart: it returns a value and a setter, and changing the value re-runs the body.Add a tap counter and a button that increments it.Button takes a label and an action. When you call setTaps(taps + 1), the runtime re-runs the body with the new value, the third Text re-renders, and the AST diff is sent to the renderer.Hooks can only be called inside a body function. If you ever see “hooks used outside a component” in development, check that you’re not calling
useState at the module top level.Add previews
Previews show how the component looks under different inputs. They appear in the component gallery, in design reviews, and anywhere the studio needs to render the component without real data. Use the Aim for previews that cover the meaningful states of the component — variants, edge-case content (long titles, empty strings), and any combination a teammate might want to inspect at a glance.
Self helper to instantiate the current component with sample props, and .previewName() to label each preview.Complete code
Here’s the full component, ready to paste into MCP App Studio.Using the component elsewhere
Once a component is published, any other component in the same package can call it by name. The studio infers the function signature from theproperties schema, so editor autocomplete shows you the available props.
What to do next
Authoring components
Metadata, body, previews, and the full
defineComponent shape.Properties
Every property helper, validation, and inspector control.
MCP host integration
Turning a component into an Interactive Tool an AI host can call.
State and hooks
useState, useStore, and the runtime hook surface.