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

# Canvas component reference

> Every component type Canvas can render — text, button, input, dropdown, list, link, divider — with props, interaction payloads, and conditional visibility

Canvas responses are arrays of component objects. Sleekplan also accepts a single object and wraps it in an array automatically. This page documents every supported component and how interactions post values back to your endpoint.

## Response format

```json theme={"system"}
[
  { "type": "text", "text": "Hello", "style": "header" },
  { "type": "button", "id": "btn-1", "label": "Continue", "style": "blue", "action": { "type": "submit" } }
]
```

Every component has a `type` field; most have an `id` that is used as the key in interaction payloads.

## Components

<AccordionGroup>
  <Accordion title="text">
    Renders a block of text. Use `"header"` for a prominent heading or `"paragraph"` for body copy.

    <ParamField body="type" type="string" required>
      Must be `"text"`.
    </ParamField>

    <ParamField body="text" type="string" required>
      The string to display.
    </ParamField>

    <ParamField body="style" type="string" required>
      Controls the visual treatment. Accepted values: `"header"` or `"paragraph"`.
    </ParamField>

    ```json theme={"system"}
    { "type": "text", "text": "Search or create a DevOps item", "style": "header" }
    ```

    No interaction — text components do not post values.
  </Accordion>

  <Accordion title="divider">
    Renders a horizontal rule to visually separate sections of the canvas.

    <ParamField body="type" type="string" required>
      Must be `"divider"`.
    </ParamField>

    ```json theme={"system"}
    { "type": "divider" }
    ```

    No interaction.
  </Accordion>

  <Accordion title="button">
    Renders a clickable button. When clicked, Sleekplan posts `{ [id]: true }` back to your endpoint.

    <ParamField body="type" type="string" required>
      Must be `"button"`.
    </ParamField>

    <ParamField body="id" type="string" required>
      Unique identifier for this component. Used as the key in the interaction payload.
    </ParamField>

    <ParamField body="label" type="string" required>
      Text displayed on the button.
    </ParamField>

    <ParamField body="style" type="string" required>
      Visual style of the button. Use `"blue"` for a primary action button.
    </ParamField>

    <ParamField body="action" type="object" required>
      Defines what happens when the button is clicked. Contains:

      * `type` — `"submit"` to post back to your Canvas endpoint, or `"link"` to navigate to a URL.
      * `href` — Required when `type` is `"link"`. The URL to open.
    </ParamField>

    ```json theme={"system"}
    {
      "type": "button",
      "id": "button-action-create",
      "label": "Create new item",
      "style": "blue",
      "action": { "type": "submit" }
    }
    ```

    **Interaction:** clicking the button posts `{ "button-action-create": true }`.
  </Accordion>

  <Accordion title="input">
    Renders a single-line text input. Submitted value is posted as `{ [id]: <value> }`.

    <ParamField body="type" type="string" required>
      Must be `"input"`.
    </ParamField>

    <ParamField body="id" type="string" required>
      Unique identifier. Used as the key in the interaction payload.
    </ParamField>

    <ParamField body="label" type="string" required>
      Placeholder text shown inside the input field.
    </ParamField>

    <ParamField body="title" type="string">
      Optional label rendered above the input field.
    </ParamField>

    <ParamField body="submit" type="boolean">
      When `true`, pressing Enter or the submit arrow submits the form immediately.
    </ParamField>

    ```json theme={"system"}
    {
      "type": "input",
      "id": "input-action-search",
      "label": "Search...",
      "title": "Search items",
      "submit": true
    }
    ```

    **Interaction:** submitting the input posts `{ "input-action-search": "<entered value>" }`.
  </Accordion>

  <Accordion title="textarea">
    Renders a multi-line text area. Follows the same interaction model as `input`.

    <ParamField body="type" type="string" required>
      Must be `"textarea"`.
    </ParamField>

    <ParamField body="id" type="string" required>
      Unique identifier. Used as the key in the interaction payload.
    </ParamField>

    <ParamField body="label" type="string" required>
      Placeholder text shown inside the textarea.
    </ParamField>

    <ParamField body="title" type="string">
      Optional label rendered above the textarea.
    </ParamField>

    <ParamField body="submit" type="boolean">
      When `true`, pressing Enter or the submit arrow submits the form immediately.
    </ParamField>

    ```json theme={"system"}
    {
      "type": "textarea",
      "id": "create-item-description",
      "label": "Describe the issue...",
      "title": "Description"
    }
    ```

    **Interaction:** submitting the textarea posts `{ "create-item-description": "<entered value>" }`.
  </Accordion>

  <Accordion title="dropdown">
    Renders a select dropdown populated with a list of options. When the admin picks an option, its `id` is posted back.

    <ParamField body="type" type="string" required>
      Must be `"dropdown"`.
    </ParamField>

    <ParamField body="id" type="string" required>
      Unique identifier. Used as the key in the interaction payload.
    </ParamField>

    <ParamField body="title" type="string" required>
      Label displayed above the dropdown.
    </ParamField>

    <ParamField body="options" type="array" required>
      Array of option objects, each with:

      * `id` — value posted when this option is selected.
      * `text` — label displayed in the dropdown.
    </ParamField>

    ```json theme={"system"}
    {
      "type": "dropdown",
      "id": "create-item-project",
      "title": "Project",
      "options": [
        { "id": "proj_abc", "text": "Project Alpha" },
        { "id": "proj_def", "text": "Project Beta" }
      ]
    }
    ```

    **Interaction:** selecting an option posts `{ "create-item-project": "proj_abc" }`.
  </Accordion>

  <Accordion title="link">
    Renders a hyperlink, optionally with a label above it. No interaction is posted.

    <ParamField body="type" type="string" required>
      Must be `"link"`.
    </ParamField>

    <ParamField body="text" type="string" required>
      The visible link text.
    </ParamField>

    <ParamField body="href" type="string" required>
      The URL the link points to.
    </ParamField>

    <ParamField body="title" type="string">
      Optional label rendered above the link.
    </ParamField>

    ```json theme={"system"}
    {
      "type": "link",
      "title": "Linked with:",
      "text": "DevOps #42",
      "href": "https://devops.example.com/items/42"
    }
    ```

    No interaction — link components do not post values.
  </Accordion>

  <Accordion title="list">
    Renders a labeled list of items. Each item is either a selectable `"option"` or a `"link"`. When the admin selects an option item, the item's `id` is posted under the list's `id`.

    <ParamField body="type" type="string" required>
      Must be `"list"`.
    </ParamField>

    <ParamField body="id" type="string" required>
      Unique identifier for the list. Used as the key in the interaction payload.
    </ParamField>

    <ParamField body="title" type="string" required>
      Heading displayed above the list.
    </ParamField>

    <ParamField body="items" type="array" required>
      Array of item objects. Each item is one of:

      * `{ "type": "option", "id": <value>, "text": <string> }` — a selectable row. When clicked, posts `{ [list.id]: <item.id> }`. The `id` can be a nested object (for example `{ "item_id": 42, "project_id": "p1" }`), and the whole object is posted back.
      * `{ "type": "link", "href": <string>, "text": <string> }` — a row that opens a URL. No interaction is posted.
    </ParamField>

    ```json theme={"system"}
    {
      "type": "list",
      "id": "link-item-list",
      "title": "Items",
      "items": [
        { "type": "option", "id": { "item_id": 42, "project_id": "p1" }, "text": "Item #42 - Task" },
        { "type": "option", "id": { "item_id": 43, "project_id": "p2" }, "text": "Item #43 - Bug" }
      ]
    }
    ```

    **Interaction:** selecting the first option posts `{ "link-item-list": { "item_id": 42, "project_id": "p1" } }`.
  </Accordion>
</AccordionGroup>

## Conditional visibility

Any component accepts an optional `condition` object. When present, Sleekplan shows the component only when the value of the field identified by `condition.value` matches the string in `condition.key`.

```json theme={"system"}
{
  "type": "dropdown",
  "id": "create-item-type",
  "title": "Item Type",
  "condition": { "value": "create-item-project", "key": "proj_abc" },
  "options": [
    { "id": "Task", "text": "Task" },
    { "id": "Bug", "text": "Bug" }
  ]
}
```

In the example above, the dropdown is only visible when the `create-item-project` field currently holds the value `"proj_abc"`.

## Inline errors

To display a section-level error, return the first element with an `error` key instead of a `type` key.

```json theme={"system"}
[{ "error": "Could not connect to DevOps. Check your credentials and try again." }]
```

Sleekplan renders the message inline at the top of the canvas panel.

## End-to-end flow

The following sequence shows how a complete link-creation flow might look across three round trips.

### Initial render

The view loads and your server returns a search input and a create button.

```json theme={"system"}
[
  { "type": "text", "text": "Search or create DevOps item", "style": "paragraph" },
  { "type": "input", "id": "input-action-search", "label": "Search...", "submit": true, "placeholder": "leave blank to skip" },
  { "type": "button", "id": "button-action-create", "label": "Create new item", "style": "blue", "action": { "type": "submit" } }
]
```

### After search submitted

The admin typed a query and submitted. Your server returns a list of matching items alongside the create button.

```json theme={"system"}
[
  {
    "type": "list",
    "id": "link-item-list",
    "title": "Items",
    "items": [
      { "type": "option", "id": { "item_id": 42, "project_id": "p1" }, "text": "Item #42 - Task" },
      { "type": "option", "id": { "item_id": 43, "project_id": "p2" }, "text": "Item #43 - Bug" }
    ]
  },
  { "type": "button", "id": "button-action-create", "label": "Create new item", "style": "blue", "action": { "type": "submit" } }
]
```

### After link selected

The admin selected an item. Your server linked it and returns a confirmation with an unlink button.

```json theme={"system"}
[
  { "type": "link", "title": "Linked with:", "text": "DevOps #42", "href": "https://devops.example.com/items/42" },
  { "type": "button", "id": "button-action-unlink", "label": "Unlink item", "style": "blue", "action": { "type": "submit" } }
]
```
