Skip to main content
defineComponent(config: {
    metadata?: Metadata;
    properties?: Record<string, PropertyField>;
    body: (props: ComponentProps, children: Component[]) => Component;
    thumbnail?: string | Component;
    previews?: (() => Component[]) | Component[];
}): ComponentCallable;
config
object
required
The component configuration object.

Returns

A ComponentCallable that serves as both the component’s default export and a callable function. When called with props, it creates an instance of the component. The returned value also carries the metadata, properties, thumbnail, and previews for the Composer to read.

Usage

Minimal component

const body = () => Text("Hello, World!")

exports.default = defineComponent({ body })

With properties

const body = (props) => {
    return VStack([
        Text(props.title).font("headline"),
        Text(props.subtitle).foregroundStyle(Color("secondary"))
    ])
}

const properties = {
    title: PropertyString({ defaultValue: "Hello" }),
    subtitle: PropertyString({ defaultValue: "World" })
}

exports.default = defineComponent({ body, properties })

With metadata and previews

const body = (props) => {
    return VStack({ spacing: 12 }, [
        Image({ url: props.imageURL })
            .resizable()
            .scaledToFill()
            .frame({ height: 200 })
            .clipShape("roundedRectangle", { cornerRadius: 12 }),
        Text(props.title).font("headline"),
        Text(props.description)
            .foregroundStyle(Color("secondary"))
    ])
}

const properties = {
    title: PropertyString({ defaultValue: "Card Title" }),
    description: PropertyString({ defaultValue: "A short description." }),
    imageURL: PropertyString({ defaultValue: "https://picsum.photos/400/200" })
}

const metadata = {
    title: "Info Card",
    description: "A card with an image, title, and description.",
    category: "Content"
}

const previews = [
    Self({
        title: "Welcome",
        description: "Get started",
        imageURL: "https://picsum.photos/400/200"
    }).previewName("Default"),
    Self({
        title: "Error",
        description: "Something went wrong",
        imageURL: "https://picsum.photos/400/200"
    }).previewName("Error State")
]

exports.default = defineComponent({ body, metadata, properties, previews })

With children

const body = (props, children) => {
    return VStack({ spacing: props.spacing }, children)
        .padding(16)
        .background(Color(props.backgroundColor))
        .cornerRadius(12)
}

const properties = {
    spacing: PropertyNumber({ defaultValue: 8 }),
    backgroundColor: PropertyString({ defaultValue: "background" })
}

exports.default = defineComponent({ body, properties })

With thumbnail

const body = (props) => Text(props.label).font("body")

const properties = {
    label: PropertyString({ defaultValue: "Hello" })
}

const thumbnail = '<svg viewBox="0 0 24 24"><text x="4" y="16" font-size="12">Aa</text></svg>'

exports.default = defineComponent({ body, properties, thumbnail })

Notes

  • The body function is called on every re-render. Avoid expensive computations inside it, or use hooks like useState to cache values.
  • Self() is available inside body and in previews to create instances of the component being defined. Props passed to Self() are typed based on the properties schema.
  • The component must be assigned to exports.default to be recognized by the BindJS runtime.
  • Properties can also be defined as a factory function () => Record<string, PropertyField> for dynamic schema generation.

See Also