Guides

Building Components

Components are reusable UI blocks -- buttons, cards, headers, footers -- that you define once and use across pages. Each component has a visual structure and a prop interface that controls what content editors can change.


Creating a Component

  1. Press C to open the Components tab in the sidebar, or click its tab.

  2. Click the + button to create a new component.

  3. Enter a name (e.g., HeroSection, ProductCard, NavLink). Use PascalCase.

  4. The editor switches to component editing mode. You see an empty canvas with a root element.

  5. Build the component's DOM tree using the Command Palette (Cmd+E) to add elements.

Creating a Component from Selection

If you have already built a section on a page and want to turn it into a component:

  1. Select the element (or group of elements) on the canvas.

  2. Use the Command Palette (Cmd+E) and search for "Create Component."

  3. Name the component.

  4. The selected elements become the component's structure, and the original elements are replaced with a component instance.

Editing a Component

To go back to a component for editing:

  1. Open the Components tab (C).

  2. Find the component in the list.

  3. Press Enter or double-click the component name to open it in the editor.

  4. Make your changes -- the structure and interface are editable.

  5. Press Escape or Shift to exit component editing mode and return to the page.

All instances of the component across your project update automatically.

Defining Props

Props are the editable "knobs" that content editors use to customize each instance of your component.

  1. While editing a component, switch to the Interface section in the Properties panel.

  2. Click + to add a new prop.

  3. Give it a name (e.g., title, variant, showIcon).

  4. Choose a type from the table below.

  5. Set a default value.

Prop Types

Type

Input Control

Default Value Example

Notes

string

Text input

"Hello World"

Plain text

number

Number input

0

Numeric value

boolean

Toggle switch

false

On/off flag

select

Dropdown

"primary"

Must define options array

link

URL + target

{ "href": "/", "target": "_blank" }

Link object

file

File picker

""

Use accept to filter (e.g., "image/*")

rich-text

Rich text editor

"<p>Content</p>"

HTML content

Important: There is no "image" prop type. For image fields, use file with accept: "image/*":

"avatar": { "type": "file", "accept": "image/*", "default": "" }

Wiring Props to Content

Use {{propName}} template syntax in text content and attributes to connect props to the component's output.

In text content:

{
  "type": "node",
  "tag": "h2",
  "children": "{{title}}"
}

In attributes:

{
  "type": "node",
  "tag": "img",
  "attributes": {
    "src": "{{imageSrc}}",
    "alt": "{{imageAlt}}"
  }
}

In link href:

{
  "type": "link",
  "href": "{{link.href}}",
  "target": "{{link.target}}",
  "children": [
    { "type": "node", "tag": "span", "children": "{{linkText}}" }
  ]
}

Slots

A slot is a placeholder where page authors can inject custom content into your component. Think of it like a "content hole."

  1. While editing a component, use the Command Palette to add a Slot element.

  2. Position it in the structure where you want injected content to appear.

  3. When someone uses your component on a page, they can drop elements into the slot.

Important: Each component can have only one slot. If you need multiple content areas, use props instead.

Setting Category

Organize components by category to keep the Components tab tidy:

  1. While editing a component, find the Category field in the component settings.

  2. Enter a category name (e.g., ui, layout, marketing, forms).

  3. Components are grouped by category in the sidebar.

Swapping Components

To replace one component with another on a page:

  1. Open the Components tab (C).

  2. Activate Swap mode in the Components sidebar.

  3. Select the component instance on the canvas that you want to replace.

  4. Click the new component in the sidebar list.

  5. The instance is swapped, and matching prop names carry their values over.

Reserved Names

Important: Never use "children" as a prop name in your component interface. It is reserved for the node tree's child elements and will cause conflicts.

Components with JavaScript

For interactive behavior (dropdowns, modals, accordions), create a JavaScript file alongside the component JSON file:

  • Button.json -- Component definition

  • Button.js -- Interactive behavior

The JS file is loaded automatically. See the JavaScript guide for details.

Important: JavaScript lives in a separate .js file, never inline in the JSON.


Under the Hood

Component JSON Format

Components are stored as JSON files in the components/ directory:

{
  "component": {
    "structure": {
      "type": "node",
      "tag": "div",
      "style": {
        "base": {
          "padding": "24px",
          "borderRadius": "8px",
          "backgroundColor": "var(--surface)"
        }
      },
      "children": [
        {
          "type": "node",
          "tag": "img",
          "attributes": {
            "src": "{{image}}",
            "alt": "{{imageAlt}}",
            "loading": "lazy"
          },
          "style": {
            "base": {
              "width": "100%",
              "borderRadius": "4px"
            }
          }
        },
        {
          "type": "node",
          "tag": "h3",
          "children": "{{title}}"
        },
        {
          "type": "node",
          "tag": "p",
          "children": "{{description}}"
        }
      ]
    },
    "interface": {
      "title": {
        "type": "string",
        "default": "Card Title"
      },
      "description": {
        "type": "string",
        "default": "Card description text."
      },
      "image": {
        "type": "file",
        "accept": "image/*",
        "default": ""
      },
      "imageAlt": {
        "type": "string",
        "default": "Card image"
      },
      "variant": {
        "type": "select",
        "options": ["default", "featured", "compact"],
        "default": "default"
      }
    },
    "category": "ui"
  }
}

Component Instance on a Page

When you place a component on a page, the page JSON contains a component instance node:

{
  "type": "component",
  "component": "ProductCard",
  "props": {
    "title": "Running Shoes",
    "description": "Lightweight and fast.",
    "image": "/images/shoes.jpg",
    "variant": "featured"
  }
}

Only the props that differ from defaults need to be specified.

Structure with a Slot

A component that accepts injected content uses a slot marker:

{
  "component": {
    "structure": {
      "type": "node",
      "tag": "section",
      "children": [
        {
          "type": "node",
          "tag": "h2",
          "children": "{{heading}}"
        },
        {
          "type": "slot"
        }
      ]
    },
    "interface": {
      "heading": {
        "type": "string",
        "default": "Section Title"
      }
    }
  }
}

On the page, the component instance can have children that fill the slot:

{
  "type": "component",
  "component": "ContentSection",
  "props": { "heading": "Our Story" },
  "children": [
    { "type": "node", "tag": "p", "children": "We started in 2020..." },
    { "type": "node", "tag": "p", "children": "Today we serve thousands of customers." }
  ]
}

Style Mappings in Components

Props can drive dynamic styles using style mappings. For example, a variant prop can change the background color:

"style": {
  "base": {
    "backgroundColor": {
      "_mapping": true,
      "prop": "variant",
      "values": {
        "primary": "var(--primary)",
        "secondary": "var(--secondary)",
        "outline": "transparent"
      }
    }
  }
}

See the Styling guide for more on style mappings.


Next Steps

Building the future of digital experiences, one website at a time

© 2026 Company. All rights reserved.