Skip to content

ExpressiveCSS

Browse documentation

Message

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

View as Markdown

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. 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

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>

Actions

Message actions such as copy, feedback or retry go in the footer as icon buttons. 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…

<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

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

No matching pages

  • Source color

    The seed every generated ramp derives from. Pick one and browse the docs — the whole theme follows. Error does not: it is a fixed hue.

    Default source: Mist Iris.

    ExpressiveCSS presets: Lagoon, Harbor, Breeze, Cobalt, Iris.

    Bold

    Soft

    Mist

    Glow