> ## Documentation Index
> Fetch the complete documentation index at: https://docs.relayapp.im/llms.txt
> Use this file to discover all available pages before exploring further.

# Message components

> Send native buttons, selects, cards, confirmations, and agent permission requests as data parts.

Message components are recognized `data` parts inside an ordinary Relay message. They stay in the canonical transcript, preserve part order, and use the same idempotent send path as text and media.

Components are conversational decisions, not app surfaces: no pagination, toggles, dashboards, or silent interactions. Kinds requiring interactions without a visible transcript artifact are rejected.

<Columns cols={2}>
  <Card title="Buttons" href="/components/buttons">
    A vertical stack with up to five options.
  </Card>

  <Card title="Select" href="/components/select">
    A collapsed row that opens a native single-select sheet.
  </Card>

  <Card title="Card" href="/components/card">
    A slot-based media card with up to two actions.
  </Card>

  <Card title="Confirm" href="/components/confirm">
    A two-role confirm and deny decision.
  </Card>

  <Card title="Agent permission request" href="/components/agent_permission_request">
    The permission component already emitted by relayapp integrations.
  </Card>
</Columns>

## One message path

An agent sends a component as `{ "type": "data", "data": { "kind": "…" } }`. Relay validates recognized v1 kinds and adds `data.fallback` when it is absent. A tap sends a normal user message whose data part identifies the source option:

```json theme={null}
{
  "parts": [
    {
      "type": "data",
      "data": {
        "origin": {
          "kind": "data_action",
          "message_id": "msg_01JZM4Q9VN",
          "part_index": 0,
          "option_id": "book",
          "source_kind": "buttons"
        },
        "option_id": "book",
        "label": "Book it"
      }
    }
  ],
  "fallback_text": "Book it"
}
```

If an option already carries `origin`, as permission options do, the client echoes that object verbatim.

`option_ids` (array) is reserved as the future multi-select tap-result shape. Version 1 is single-select; do not emit or interpret `option_ids` yet.

## Common option fields

| Field         | Required | Contract                                                                                                |
| ------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `id`          | Yes      | 1–200 bytes, unique within the part, `[A-Za-z0-9_.:-]`; this ASCII charset makes bytes equal characters |
| `label`       | Yes      | 1–24 characters                                                                                         |
| `description` | No       | Up to 72 characters; select rows and card actions only                                                  |
| `style`       | No       | `default`, `primary`, or `danger`; at most one `primary` per part                                       |
| `url`         | No       | Credential-free HTTPS link-out; an option with a URL does not send a postback tap                       |
| `disabled`    | No       | `true` renders the option non-tappable and excludes it from synthesized fallback numbering              |

Every recognized component prompt is limited to 1,024 characters. A message may contain at most four recognized component data parts, and every data part remains subject to the 16 KB limit.

## Fallback and compatibility

Relay synthesizes a missing component fallback from the prompt or title followed by numbered option labels. Clients use that string when they do not support the kind or when `features.postback_interactions` is `false`.

The feature flag controls client rendering only. It does not block component sending, validation, or storage. Unknown `data.kind` values pass through unchanged so clients can render `data.fallback` or the message-level `fallback_text`. Consumers must ignore unknown fields inside known kinds.

<Warning>
  Component parts are valid only in 1:1 threads in v1. The server returns `422 invalid_request` when a message with component parts targets a group conversation. Group tap semantics is an open question for the groups component release.
</Warning>

<Note>
  [Quick-reply suggestions](/guides/sending-messages#quick-replies) are a separate feature. Suggestions are transient chips attached to the newest message and send their visible text. Components are durable transcript parts and return an origin-tagged data message.
</Note>

The machine-readable registry is `docs/components/catalog.json`. Each catalog entry points to its standalone schema under `schemas/parts/` and its send, stored, and tap-result examples under `examples/components/`.

## See also

* [Sending messages](/guides/sending-messages)
* [Buttons component](/components/buttons)
* [Select component](/components/select)
* [Confirm component](/components/confirm)
* [Card component](/components/card)
