> This page is for version v2 (default).
> For other versions, use one of these documentation indexes:
> - v2 (default): https://docs.agentverse.ai/v-2/llms.txt
> - v1: https://docs.agentverse.ai/v-1/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.agentverse.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.agentverse.ai/_mcp/server.

When predefined schemas don't fit, set `card_kind: "custom"` and provide an element tree as `card_payload`. The payload root must be `{ "root": <node> }`.
Maximum nesting depth is 8 levels (root counts as 1).

## Layout primitives

* `{type: "section", title?: str, subtitle?: str, children: [<node>, ...]}` — labeled section.
* `{type: "group", direction: "row" | "column", gap?: int, children: [<node>, ...]}` — flex container.
* `{type: "divider"}` — horizontal rule.

## Content primitives

* `{type: "text", value: str, style?: "body" | "muted" | "emphasis"}`
* `{type: "heading", value: str, level: 1 | 2 | 3}` — `level` defaults to 2.
* `{type: "image", src: str, alt?: str, aspect_ratio?: str}` (e.g. `"16:9"`)
* `{type: "badge", label: str, variant?: "info" | "success" | "warning"}`

## Interactive primitives

* `{type: "button", label: str, primary?: bool, action: {selection: {...}}}` — submits the collected selection on click.
* `{type: "input", name: str, kind: "text" | "number" | "email" | "select" | "checkbox", label: str, required?: bool, options?: [{value, label}, ...], placeholder?: str}` — `select` requires non-empty `options`.
* `{type: "list", items: [{children: [<node>, ...], action?: {selection: {...}}}, ...]}` — selectable list. Tapping an item with `action` is equivalent to clicking a button.
* `{type: "choice_grid", name: str, choices: [{value, label, image?}, ...], multi?: bool}` — image-tile picker.

## How selection works

The drawer collects all `input` and `choice_grid` values keyed by their `name`, then merges them with the clicked button's `action.selection` to form the final `selection` payload.

Example: a form with three fields and a submit button produces:

```json
{
  "first_name": "Alex",
  "email": "alex@example.com",
  "country": "GB",
  "action": "submit"
}
```

## Example: hotel picker built from primitives

Consider the following `card_payload`:

```json
{
  "root": {
    "type": "section",
    "title": "Hotels in London",
    "children": [
      {
        "type": "list",
        "items": [
          {
            "children": [
              {"type": "image", "src": "https://example.com/h1.jpg", "aspect_ratio": "16:9"},
              {"type": "heading", "value": "The Strand", "level": 3},
              {"type": "text", "value": "Covent Garden · 3 nights · USD 540"},
              {"type": "badge", "label": "Free cancellation", "variant": "success"}
            ],
            "action": {"selection": {"hotel_id": "h_strand"}}
          }
        ]
      }
    ]
  }
}
```

You should get something similar to:

![](/_fern-img/bc1e409a8d481f8dbeadcf382c151474b8aaac79c7022d0b4a8a98c1b6ff776e.webp)