# Message

> One message in a conversation, with an optional avatar, header and footer.

## Anatomy

A `.message` lays out one message in a conversation. It places an optional avatar, header and footer around a single surface, usually a `.message-bubble`. Messages sit on the start side. Add `end` for the sender's own messages.

Every child that is not the avatar, header or footer counts as the surface, so a message has one surface. To keep a bubble and an attachment together, wrap them in a `<div>`, or use a [group](#group). Write the parts as `<div>` elements. A `<header>` or `<footer>` outside sectioning content becomes a page landmark.

Deploying to prod real quick.

It's 4:55 PM. On a Friday.

```
<div role="log" aria-label="Conversation with Oliver">
  <div class="message end">
    <p class="message-bubble">Deploying to prod real quick.</p>
  </div>
  <div class="message">
    <p class="message-bubble">It's 4:55 PM. On a Friday.</p>
  </div>
</div>
```

Put `role="log"` on the conversation so screen readers announce messages appended to it. Leave it off a transcript that does not change.

## Avatar

Put a `.message-avatar` first in the message. It anchors to the bottom of the surface and stays clear of the footer. On an `end` message it moves to the end. The avatar is an `<img>`, or a `<span>` holding initials or an icon. Give the image an empty `alt` when a header already names the sender.

![You](https://picsum.photos/id/64/64/64)

It's a one-line change.

OL

Alright, let me take a look.

```
<div class="message end">
  <img class="message-avatar" src="me.jpg" alt="You">
  <p class="message-bubble">It's a one-line change.</p>
</div>
<div class="message">
  <span class="message-avatar" role="img" aria-label="Oliver">OL</span>
  <p class="message-bubble">Alright, let me take a look.</p>
</div>
```

## Group

A `.message-group` stacks consecutive messages from one sender and joins their bubbles on the sender's side. Give the earlier messages an empty `.message-avatar` so they line up with the avatar on the last one.

I checked the registry addresses.

OL

The component and example JSON now live under the UI registry.

```
<div class="message-group">
  <div class="message">
    <span class="message-avatar"></span>
    <p class="message-bubble">I checked the registry addresses.</p>
  </div>
  <div class="message">
    <span class="message-avatar" role="img" aria-label="Oliver">OL</span>
    <p class="message-bubble">The component and example JSON now live under the UI registry.</p>
  </div>
</div>
```

## Header and footer

A `.message-header` above the surface holds the sender's name. A `.message-footer` below it holds metadata such as delivery or read status. Both follow the message to its side.

Olivia

I already checked the logs.

Send the report to the team. Ping @shadcn if you need help.

**Read** Yesterday

```
<div class="message">
  <div class="message-header">Olivia</div>
  <p class="message-bubble">I already checked the logs.</p>
</div>
<div class="message end">
  <p class="message-bubble">Send the report to the team. Ping @shadcn if you need help.</p>
  <div class="message-footer"><strong>Read</strong> Yesterday</div>
</div>
```

## Actions

Message actions such as copy, feedback or retry go in the footer as [icon buttons](/icon-buttons.html.md). Each needs an `aria-label`. On an `end` message the actions stay on the end side.

The install failure is coming from the workspace package.

Okay drop me a link. Taking a look…

Failed to send

```
<div class="message">
  <p class="message-bubble">The install failure is coming from the workspace package.</p>
  <div class="message-footer">
    <button class="icon-button xsmall" aria-label="Copy">
      <span class="material-symbols" aria-hidden="true">content_copy</span>
    </button>
    <button class="icon-button xsmall" aria-label="Good response">
      <span class="material-symbols" aria-hidden="true">thumb_up</span>
    </button>
  </div>
</div>
<div class="message end">
  <p class="message-bubble">Okay drop me a link. Taking a look…</p>
  <div class="message-footer">
    <span class="error-text">Failed to send</span>
    <button class="icon-button xsmall" aria-label="Retry">
      <span class="material-symbols" aria-hidden="true">refresh</span>
    </button>
  </div>
</div>
```

## Attachments

Use an `outlined` bubble, which has no fill, for attachments and other rich content. A bubble whose only child is an image or video frames it with a thin inset. Send several items as a group.

![Office corridor with glass walls](https://picsum.photos/id/1048/160/160)

Here's the image. Can you add it to the PDF? Use it for the cover page.

Done. Here's the PDF with the image added as the cover page.

sales-dashboard.pdf

PDF · 2.4 MB

```
<div class="message end">
  <div class="message-bubble outlined">
    <img src="office.jpg" alt="Office corridor with glass walls" width="80" height="80">
  </div>
</div>

<div class="message">
  <div class="message-bubble outlined flex align-center gap-3">
    <span class="material-symbols" aria-hidden="true">description</span>
    <div class="min-w-0">
      <div class="title-small truncate">sales-dashboard.pdf</div>
      <div class="body-small">PDF · 2.4 MB</div>
    </div>
    <a class="icon-button" href="sales-dashboard.pdf" download aria-label="Download sales-dashboard.pdf">
      <span class="material-symbols" aria-hidden="true">download</span>
    </a>
  </div>
</div>
```

## Tokens

Override these on the `.message`, or on `.message-group` for the group gap.

| Token | Default |
| --- | --- |
| `--md-comp-message-avatar-size` | 32px |
| `--md-comp-message-gap` | 8px |
| `--md-comp-message-surface-max-width` | 80% |
| `--md-comp-message-bubble-shape` | 20px |
| `--md-comp-message-bubble-grouped-shape` | 4px |
| `--md-comp-message-bubble-container-color` | `--md-sys-color-surface-container-high`; `end`: `--md-sys-color-primary-container` |
| `--md-comp-message-bubble-color` | `--md-sys-color-on-surface`; `end`: `--md-sys-color-on-primary-container` |
| `--md-comp-message-group-gap` | 2px |
