# `hb-messages-list`

**Category:** messaging · **Tags:** messaging, chat · **Package:** `@htmlbricks/hb-messages-list`

## Description

`hb-messages-list` renders a scrollable transcript of chat messages. Each row joins a message to its author from the `authors` list, aligns the current user (`me: true`) to one side and everyone else to the other, and can show names, avatars, timestamps, and optional per-message action buttons. When `options.bubbles` is enabled, self vs peer bubbles use different surfaces and expose distinct CSS parts; when it is off, messages use a shared neutral bubble part.

Messages are **filtered**: only items whose `authorId` matches an author in `authors` are shown. Avatars collapse for **consecutive** messages from the same author if the gap between timestamps is under **five minutes** (the avatar column still reserves space when avatars are enabled).

The component loads **Bootstrap Icons** (via the shadow root stylesheet) for action buttons: each action’s `icon` value becomes the `bi-{icon}` class name.

## Message content and `type`

The `TMessage.type` field supports `"text" | "image" | "video" | "audio" | "file" | "code"`. In the current markup, only **`code`** is rendered differently (language tag when `language` is set, then a `<pre><code>` block). All other types, including `image`, `video`, `audio`, and `file`, are shown as **plain text** in the message body (the `text` field). Fields such as `uri`, `status`, `system`, `reply`, and `quotedMessageId` are part of the public shape for integrators but are **not** interpreted for extra UI in this component.

## Default options

If `options` is omitted or partially provided (after JSON merge), defaults are:

| Option           | Default | Effect |
|------------------|---------|--------|
| `showTimestamp`  | `true`  | Show time under or beside the message (grouped with the action row when `actions` is non-empty). |
| `showAvatar`     | `true`  | Avatar column and alignment spacers. |
| `showName`       | `true`  | Author row above the bubble; the current user is labeled **You**. |
| `bubbles`        | `false` | If `true`, self vs peer bubble parts and styling; if `false`, neutral `message` part. |

**Note:** Parsed `options` are merged with internal defaults. Property keys inside JSON attribute values follow the TypeScript / runtime shape (for example `authorId`, `showTimestamp`, `isAI`); booleans use JSON `true` / `false`.

## Actions and events

When `actions` is a non-empty array, each message row renders small outline buttons. Each action is `{ "icon": string, "name": string }` where `icon` is a Bootstrap Icons suffix (for example `"clipboard"` → `bi-clipboard`).

| Event    | `detail` |
|----------|----------|
| `action` | `{ messageId: string; action: string }` — `action` is the `name` from the clicked action. |

## Timestamps

Displayed times are derived with `Date` from `message.timestamp` (ISO strings from JSON are supported). Messages from **today** show time only; older messages show a locale-dependent date plus time.

## AI authors

If an author has `isAI: true`, the default avatar uses an AI-specific placeholder and a small **AI** badge appears when the avatar is visible.

## Custom element

`hb-messages-list`

## Attributes (snake_case; string values in HTML)

Complex props are **JSON strings** on attributes (the component parses them in effects). Arrays and objects must be valid JSON.

| Attribute   | Required | Description |
|-------------|----------|-------------|
| `id`        | No       | Optional element id. |
| `style`     | No       | Optional host inline style (typed on the component; use as for any HTMLElement). |
| `messages`  | Yes      | JSON array of `TMessage`. Each message should include `authorId` matching an author `id`. |
| `authors`   | Yes      | JSON array of `TAuthor`. |
| `options`   | No       | JSON object: `showTimestamp`, `showAvatar`, `showName`, `bubbles` (all optional booleans). |
| `actions`   | No       | JSON array of `{ "icon": string, "name": string }` for per-message buttons. |

## Styling

### Bulma theme variables (`:host`)

Documented in `extra/docs.ts` — override on the host with **`--bulma-*`** (see [Bulma CSS variables](https://bulma.io/documentation/features/css-variables/)).

| Variable | Purpose |
|----------|---------|
| `--bulma-primary` | Self bubble background and accents. |
| `--bulma-primary-invert` | Text on primary bubble background. |
| `--bulma-border` | Peer / neutral bubble borders. |
| `--bulma-text` | Default message and caption color inside bubbles. |
| `--bulma-text-weak` | Muted text (timestamps, You label). |
| `--bulma-scheme-main-bis` | Light bubble / neutral backgrounds. |
| `--bulma-radius-large` | Bubble corner radius. |
| `--bulma-radius-rounded` | Circular action buttons and avatars. |

### Component variables

| Variable | Default | Purpose |
|----------|---------|---------|
| `--hb-messages-list-max-height` | `600px` | Scrollable list max height. |
| `--hb-messages-list-padding` | `1rem` | Padding inside the host. |
| `--hb-messages-bubble-max-width-mobile` | `85%` | Max width of bubble content on small layouts. |

## CSS parts

Expose only on elements that are rendered for the current `options.bubbles` / layout branch.

| Part | When | Purpose |
|------|------|---------|
| `message-body` | Always (per message) | Inner content: text or code block. |
| `message-bubble-me` | `bubbles: true` | Bubble for the author with `me: true`. |
| `message-bubble-them` | `bubbles: true` | Bubble for other authors. |
| `message` | `bubbles: false` | Outer wrapper for the neutral bubble. |
| `message-timestamp` | When timestamps are shown | Timestamp label. |

## HTML slots

None.

## Types

```typescript
export type TMessage = {
  id: string;
  text: string;
  timestamp: Date;
  type: "text" | "image" | "video" | "audio" | "file" | "code";
  status?: "pending" | "sent" | "received" | "read";
  system?: boolean;
  reply?: boolean;
  quotedMessageId?: string;
  authorId?: string;
  uri?: string;
  language?: string; // for `type: "code"`
};

export type TAuthor = {
  id: string;
  name: string;
  avatar?: string;
  status?: "online" | "offline" | "away" | "busy";
  me?: boolean;
  isAI?: boolean;
};

export type Component = {
  id?: string;
  style?: string;
  messages: TMessage[];
  authors: TAuthor[];
  options?: {
    showTimestamp?: boolean;
    showAvatar?: boolean;
    showName?: boolean;
    bubbles?: boolean;
  };
  actions?: { icon: string; name: string }[];
};

export type Events = {
  action: { messageId: string; action: string };
};
```

## Examples

### Minimal markup

```html
<hb-messages-list
  id="thread"
  messages='[{"id":"m1","text":"Hello","timestamp":"2026-04-17T10:00:00.000Z","type":"text","authorId":"a1"}]'
  authors='[{"id":"a1","name":"You","me":true},{"id":"a2","name":"Support"}]'
></hb-messages-list>
```

### With bubbles, actions, and options

```html
<hb-messages-list
  id="messages-list-demo"
  messages='[{"id":"m1","text":"Hi","timestamp":"2026-04-17T10:00:00.000Z","type":"text","authorId":"u1"}]'
  authors='[{"id":"u1","name":"You","me":true}]'
  options='{"bubbles":true,"showTimestamp":true,"showAvatar":true,"showName":true}'
  actions='[{"icon":"clipboard","name":"copy"},{"icon":"trash","name":"delete"}]'
></hb-messages-list>
<script>
  document.getElementById("messages-list-demo").addEventListener("action", (e) => {
    console.log(e.detail.messageId, e.detail.action);
  });
</script>
```

Use valid JSON for every attribute value; escape quotes as needed for inline HTML.

## Package metadata

- **Custom element:** `hb-messages-list`
- **Package:** `@htmlbricks/hb-messages-list`
