# Message

A single message row that renders markdown, reasoning, tool calls, attachments, and action buttons from one message object.

<p class="kai-tag-sub">kai-message</p>

One element, one object — render a complete message row with markdown, reasoning, tool calls, attachments, and action buttons. The keystone of any custom message list.

## Preview

> **tip:** 
Reach for `<kai-message>` when building your own thread — a custom layout, a non-Solid app, or anywhere you iterate the message list yourself. For a full chat surface in one tag, use `<kai-chat>`. In SolidJS, compose `Message`, `MessageBody`, and `MessageActions` from `@kitn.ai/ui/solid` directly for finer control.

## Usage

Set `message` in JavaScript (objects can't be HTML attributes) and listen for `kai-message-action`:

```html
<kai-message id="msg" style="display:block;"></kai-message>

<script type="module">

  await customElements.whenDefined('kai-message');

  const msg = document.getElementById('msg');

  msg.message = {
    id: 'm-1', role: 'assistant',
    parts: [
      { type: 'reasoning', text: 'The user wants X, so I should do Y.' },
      { type: 'tool', tool: { type: 'search', state: 'output-available', output: { hits: 3 } } },
      { type: 'text', text: "Here's the plan:\n\n```js\nconst kit = useChat();\n```" },
    ],
    actions: ['copy', 'like', 'dislike', 'regenerate'],
  };

  msg.addEventListener('kai-message-action', (e) => {
    console.log(e.detail.action, e.detail.messageId);
  });
</script>
```

- **`message`** takes the whole object: `id`, `role`, an ordered `parts` array, plus optional `actions`, `avatar`, and `feedback`. There's no scalar shortcut for the text; even a single line is a `{ type: 'text', text }` part.
- **Markdown** is on by default for `role="assistant"`, off for `role="user"`. Override with the `markdown` boolean.
- **`actions`** accepts built-in names (`'copy'`, `'like'`, `'dislike'`, `'regenerate'`, `'edit'`) and/or `{ id, label, icon?, tooltip? }` descriptors. Alternatively, place `<kai-action>` children in the light DOM.
- **`actionsReveal`** — `'always'` (default) keeps the action bar visible; `'hover'` hides it until the row is hovered.

## The action row

The built-in `copy`, `like`, and `dislike` actions are wired — the element handles the interaction, you just listen for `kai-message-action`.

- **`copy`** writes the message content to the clipboard, flips its icon to a check for a couple of seconds, and raises a "Copied to clipboard" [toast](/components/toast/).
- **`like` / `dislike`** mark the chosen vote active (filled, `aria-pressed`) and animate the other one out, so the row reads as a clear yes/no. Tapping the active vote again clears it and brings both back. Setting a vote raises a "Thanks for your feedback" toast; clearing it is silent.

These survive streaming. The vote and copied state live above the message list, so a fresh `messages` array per chunk never wipes a user's vote.

### Reading and persisting the vote

`kai-message-action` carries a `state` field for the toggleable votes — `'on'` when a vote is set, `'off'` when cleared. Copy and custom actions omit it.

```js
msg.addEventListener('kai-message-action', (e) => {
  const { messageId, action, state } = e.detail;
  if (action === 'like' || action === 'dislike') {
    if (state === 'on') saveVote(messageId, action);
    else clearVote(messageId);
  }
});
```

To re-hydrate a persisted vote (e.g. on history load), set `feedback` on the message. A controlled `feedback` wins over the element's own optimistic state:

```js
msg.message = { id: 'm-1', role: 'assistant', parts: [{ type: 'text', text: '…' }],
                actions: ['copy', 'like', 'dislike'], feedback: 'like' };
```

## Examples

### Rich Assistant Message

A full assistant turn: markdown with a fenced code block, a reasoning block, a tool call, an attachment, and built-in actions.

### User Message

A plain user turn with no actions. Markdown is off by default for `role="user"`.

### Avatar and Custom Action

An avatar pulled from `message.avatar`, plus a custom `Share` action alongside built-in `copy` and `like`.

### Actions Reveal on Hover

`actions-reveal="hover"` hides the action bar until the row is hovered — cleaner in dense threads.

## Slots

Compose your own message rows: inject a per-message header or footer, or replace the avatar rail (`avatar="none"` drops it entirely). These are the keystone of a [custom message list](/patterns/compose-your-own/).

## Styling

Restyle the row, bubble, content, or action bar from outside via `::part`.

## Props

## Events

## Methods

## Composed from
