conversation / 06

Installation

tokens.css + chat-message.css + button.css + recipes/chat-message-prose.css
head.html
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="components/chat-message/chat-message.css">

Basic

chat-message / Basicinteractive

Explain React hooks like useState

Hooks let you use state in function components.

useState

jsx
const [count, setCount] = useState(0);
  • Returns [value, setter]

Code

chat-message.html + chat-message.css
chat-message
<style>
.au-chat-message {
  --au-message-gap: 8px;
  --au-message-avatar: 28px;
  --au-message-max: min(70%, 36rem);
  display: flex;
  flex-direction: column;
  gap: var(--au-message-gap);
  width: 100%;
}

.au-chat-message__avatar {
  display: none;
}

.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  gap: 12px;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
}

.au-chat-message--with-avatar.au-chat-message__avatar {
  align-items: center;
  background: var(--au-surface-muted);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  display: flex;
  font: 600 10px/1 var(--au-font-sans);
  height: var(--au-message-avatar);
  justify-content: center;
  width: var(--au-message-avatar);
}

.au-chat-message__meta {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 2px;
}

.au-chat-message__role {
  color: var(--au-fg);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.au-chat-message__time,
.au-chat-message__model {
  color: var(--au-fg-subtle);
  font: 12px/1.3 var(--au-font-sans);
}

.au-chat-message__body {
  color: var(--au-fg);
  font-size: 16px;
  letter-spacing: -0.011em;
  line-height: 1.625;
  margin: 0;
  overflow-wrap: break-word;
}

.au-chat-message__body p + p {
  margin-top: 12px;
}

.au-chat-message__body code {
  background: var(--au-surface-muted);
  border-radius: var(--au-radius-xs);
  color: var(--au-fg);
  font: 0.85em/1.4 var(--au-font-mono);
  padding: 0.12em 0.35em 0.05em;
}

.au-chat-message__details {
  margin: 0;
}

.au-chat-message__details > summary {
  color: var(--au-fg-subtle);
  cursor: pointer;
  display: inline-flex;
  font: 12px/1.3 var(--au-font-sans);
  list-style: none;
  margin-bottom: 8px;
  width: fit-content;
}

.au-chat-message__details > summary::-webkit-details-marker {
  display: none;
}

.au-chat-message__details > summary:focus-visible {
  border-radius: var(--au-radius-sm);
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}

.au-chat-message__actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 8px;
  min-height: 32px;
  padding-top: 8px;
}

.au-chat-message__actions.au-btn {
  --au-btn-height: 24px;
  --au-btn-padding-inline: 8px;
  --au-btn-radius: var(--au-radius-md);
  color: var(--au-fg-muted);
  font: 500 12px/1 var(--au-font-sans);
  min-height: 24px;
}
.au-chat-message__actions.au-btn:hover:not(:disabled) { background: var(--au-surface-muted); color: var(--au-fg); }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: scale(0.9); }

.au-chat-message--assistant {
  padding-inline: 8px;
}

.au-chat-message--assistant.au-chat-message__meta {
  display: none;
}

.au-chat-message--user {
  align-items: flex-end;
  display: grid;
  grid-template-columns: minmax(72px, 1fr) auto;
  margin-inline-start: 0;
  padding-inline: 8px;
}

.au-chat-message--user > * {
  grid-column: 2;
}

.au-chat-message--user.au-chat-message__meta {
  display: none;
}

.au-chat-message--user.au-chat-message__body,
.au-chat-message--user.au-chat-message__details {
  background: var(--au-action);
  border-radius: var(--au-radius-lg);
  color: var(--au-action-fg);
  line-height: 1.5;
  max-width: var(--au-message-max);
  padding: 12px 16px;
  width: fit-content;
}

.au-chat-message--user.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
  margin-inline-start: 0;
}

.au-chat-message--user.au-chat-message--with-avatar > * {
  grid-column: auto;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__body,
.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__details {
  background: transparent;
  border-radius: 0;
  max-width: none;
  padding: 0;
}

.au-chat-message--assistant.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--system {
  padding-inline: 8px;
}

.au-chat-message--system.au-chat-message__body {
  color: var(--au-fg-subtle);
  font-size: 13px;
  line-height: 1.5;
}

.au-chat-message--tool {
  border-top: 1px solid var(--au-border-color);
  padding-inline: 8px;
  padding-top: 16px;
}

.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after {
  animation: au-message-caret 1s step-end infinite;
  background: var(--au-fg);
  content: "";
  display: inline-block;
  height: 1.05em;
  margin-inline-start: 2px;
  vertical-align: text-bottom;
  width: 2px;
}

@keyframes au-message-caret {
  50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after { animation: none; }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: none; }
}

/* --- absorbed: quote parts --- */
/* agent-ui / quote — first-class component (promoted from host extracts). */
/* base.tsx ComposerQuotePreview / QuoteBlock — host chrome (no side-tab accent) */
.au-quote-preview {
  align-items: flex-start;
  background: color-mix(in srgb, var(--au-fg) 5%, var(--au-surface));
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  display: flex;
  gap: 8px;
  margin-bottom: 4px;
  padding: 8px 12px;
}

.au-quote-preview__text {
  color: var(--au-fg-muted);
  flex: 1;
  font: 400 13px/1.4 var(--au-font-sans);
  margin: 0;
}

.au-quote-preview__dismiss {
  --au-btn-height: 28px;
  --au-btn-padding-inline: 0;
  aspect-ratio: 1;
  min-width: 28px;
  width: 28px;
}

.au-quote-block {
  background: color-mix(in srgb, var(--au-fg) 4%, transparent);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-muted);
  font: italic 400 13px/1.45 var(--au-font-sans);
  margin: 0 0 8px;
  padding: 8px 12px;
}

.au-quote-toolbar {
  align-items: center;
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: inline-flex;
  gap: 2px;
  padding: 4px;
}
.au-quote-toolbar__btn {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg);
  cursor: pointer;
  display: inline-flex;
  font: 400 13px/1.3 var(--au-font-sans);
  gap: 8px;
  padding: 8px 12px;
}
.au-quote-toolbar__btn:hover,
.au-quote-toolbar__btn:focus-visible {
  background: var(--au-surface-muted);
  outline: 0;
}

/* --- absorbed: citation parts --- */
/* agent-ui / citation — first-class component (promoted from host extracts). */
/* Inline citations */
.au-citations {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 0;
}
.au-citation {
  background: var(--au-surface-muted);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 70%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  font: 400 12px/1.3 var(--au-font-sans);
  padding: 4px 8px;
  text-decoration: none;
}
.au-citation:hover,
.au-citation:focus-visible { color: var(--au-fg); outline: 0; }
.au-citation:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
.au-sources {
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  margin-top: 12px;
  padding: 8px 12px;
}
.au-sources > summary {
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 500 12px/1.3 var(--au-font-sans);
  list-style: none;
}
.au-sources > summary::-webkit-details-marker { display: none; }
.au-sources__list {
  display: grid;
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
}
.au-sources__item {
  color: var(--au-fg-muted);
  font: 400 12px/1.4 var(--au-font-sans);
}

/* --- absorbed: message-timing parts --- */
/* agent-ui / message-timing — first-class component (promoted from host extracts). */
/* Message timing badge + details panel (message-timing sample). */
.au-msg-timing { position: relative; }
.au-msg-timing__badge {
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  cursor: pointer;
  font: 400 12px/1 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
  list-style: none;
  padding: 8px;
}
.au-msg-timing__badge::-webkit-details-marker { display: none; }
.au-msg-timing__badge:hover,
.au-msg-timing[open] > .au-msg-timing__badge {
  background: var(--au-surface-muted);
  color: var(--au-fg);
}
.au-msg-timing__panel {
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: grid;
  gap: 8px;
  margin-top: 8px;
  min-width: 11rem;
  padding: 12px;
}
.au-msg-timing__row {
  display: flex;
  font: 400 12px/1.3 var(--au-font-sans);
  gap: 16px;
  justify-content: space-between;
}
.au-msg-timing__label { color: var(--au-fg-muted); }
.au-msg-timing__value {
  color: var(--au-fg);
  font: 400 12px/1.3 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
}

/* --- absorbed: follow-ups parts --- */
/* agent-ui / follow-ups — first-class component (promoted from host extracts). */
/* Post-reply follow-up chips (ThreadFollowupSuggestions). Host owns click → composer. */
.au-followups {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 0;
}
.au-followups__chip {
  background: var(--au-surface);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 60%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 400 13px/1.3 var(--au-font-sans);
  padding: 8px 12px;
  text-align: start;
}
@media (max-width: 640px) {
  .au-followups__chip,
  .au-quote-preview__dismiss,
  .au-quote-toolbar__btn,
  .au-msg-timing__badge,
  .au-sources > summary,
  .au-citation {
    min-height: 40px;
    min-width: 40px;
  }
}
.au-followups__chip:hover,
.au-followups__chip:focus-visible {
  background: var(--au-surface-muted);
  color: var(--au-fg);
  outline: 0;
}
.au-followups__chip:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
</style>

<div style="display: grid; gap: 8px; width: 100%;"><article class="au-chat-message au-chat-message--user"><p class="au-chat-message__body">Explain React hooks like useState</p></article><article class="au-chat-message au-chat-message--assistant"><div class="au-chat-message__body"><p>Hooks let you use state in <strong>function components</strong>.</p><h2><code>useState</code></h2><div class="au-code"><div class="au-code__header"><span>jsx</span><button type="button" class="au-btn au-btn--ghost au-btn--sm" data-au-action="copy" aria-label="Copy">⎘</button></div><pre><code>const [count, setCount] = useState(0);</code></pre></div><ul><li>Returns <code>[value, setter]</code></li></ul></div><div class="au-chat-message__actions"><button type="button" class="au-btn au-btn--ghost au-msg-action" data-au-action="copy" aria-label="Copy"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16V4a2 2 0 0 1 2-2h12"/></svg></button><button type="button" class="au-btn au-btn--ghost au-msg-action" data-au-action="regenerate" aria-label="Regenerate"><svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg></button></div></article></div>

Quote

chat-message / Quoteinteractive
Selected user text for reply context.

Code

chat-message.html + chat-message.css
chat-message
<style>
.au-chat-message {
  --au-message-gap: 8px;
  --au-message-avatar: 28px;
  --au-message-max: min(70%, 36rem);
  display: flex;
  flex-direction: column;
  gap: var(--au-message-gap);
  width: 100%;
}

.au-chat-message__avatar {
  display: none;
}

.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  gap: 12px;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
}

.au-chat-message--with-avatar.au-chat-message__avatar {
  align-items: center;
  background: var(--au-surface-muted);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  display: flex;
  font: 600 10px/1 var(--au-font-sans);
  height: var(--au-message-avatar);
  justify-content: center;
  width: var(--au-message-avatar);
}

.au-chat-message__meta {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 2px;
}

.au-chat-message__role {
  color: var(--au-fg);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.au-chat-message__time,
.au-chat-message__model {
  color: var(--au-fg-subtle);
  font: 12px/1.3 var(--au-font-sans);
}

.au-chat-message__body {
  color: var(--au-fg);
  font-size: 16px;
  letter-spacing: -0.011em;
  line-height: 1.625;
  margin: 0;
  overflow-wrap: break-word;
}

.au-chat-message__body p + p {
  margin-top: 12px;
}

.au-chat-message__body code {
  background: var(--au-surface-muted);
  border-radius: var(--au-radius-xs);
  color: var(--au-fg);
  font: 0.85em/1.4 var(--au-font-mono);
  padding: 0.12em 0.35em 0.05em;
}

.au-chat-message__details {
  margin: 0;
}

.au-chat-message__details > summary {
  color: var(--au-fg-subtle);
  cursor: pointer;
  display: inline-flex;
  font: 12px/1.3 var(--au-font-sans);
  list-style: none;
  margin-bottom: 8px;
  width: fit-content;
}

.au-chat-message__details > summary::-webkit-details-marker {
  display: none;
}

.au-chat-message__details > summary:focus-visible {
  border-radius: var(--au-radius-sm);
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}

.au-chat-message__actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 8px;
  min-height: 32px;
  padding-top: 8px;
}

.au-chat-message__actions.au-btn {
  --au-btn-height: 24px;
  --au-btn-padding-inline: 8px;
  --au-btn-radius: var(--au-radius-md);
  color: var(--au-fg-muted);
  font: 500 12px/1 var(--au-font-sans);
  min-height: 24px;
}
.au-chat-message__actions.au-btn:hover:not(:disabled) { background: var(--au-surface-muted); color: var(--au-fg); }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: scale(0.9); }

.au-chat-message--assistant {
  padding-inline: 8px;
}

.au-chat-message--assistant.au-chat-message__meta {
  display: none;
}

.au-chat-message--user {
  align-items: flex-end;
  display: grid;
  grid-template-columns: minmax(72px, 1fr) auto;
  margin-inline-start: 0;
  padding-inline: 8px;
}

.au-chat-message--user > * {
  grid-column: 2;
}

.au-chat-message--user.au-chat-message__meta {
  display: none;
}

.au-chat-message--user.au-chat-message__body,
.au-chat-message--user.au-chat-message__details {
  background: var(--au-action);
  border-radius: var(--au-radius-lg);
  color: var(--au-action-fg);
  line-height: 1.5;
  max-width: var(--au-message-max);
  padding: 12px 16px;
  width: fit-content;
}

.au-chat-message--user.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
  margin-inline-start: 0;
}

.au-chat-message--user.au-chat-message--with-avatar > * {
  grid-column: auto;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__body,
.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__details {
  background: transparent;
  border-radius: 0;
  max-width: none;
  padding: 0;
}

.au-chat-message--assistant.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--system {
  padding-inline: 8px;
}

.au-chat-message--system.au-chat-message__body {
  color: var(--au-fg-subtle);
  font-size: 13px;
  line-height: 1.5;
}

.au-chat-message--tool {
  border-top: 1px solid var(--au-border-color);
  padding-inline: 8px;
  padding-top: 16px;
}

.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after {
  animation: au-message-caret 1s step-end infinite;
  background: var(--au-fg);
  content: "";
  display: inline-block;
  height: 1.05em;
  margin-inline-start: 2px;
  vertical-align: text-bottom;
  width: 2px;
}

@keyframes au-message-caret {
  50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after { animation: none; }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: none; }
}

/* --- absorbed: quote parts --- */
/* agent-ui / quote — first-class component (promoted from host extracts). */
/* base.tsx ComposerQuotePreview / QuoteBlock — host chrome (no side-tab accent) */
.au-quote-preview {
  align-items: flex-start;
  background: color-mix(in srgb, var(--au-fg) 5%, var(--au-surface));
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  display: flex;
  gap: 8px;
  margin-bottom: 4px;
  padding: 8px 12px;
}

.au-quote-preview__text {
  color: var(--au-fg-muted);
  flex: 1;
  font: 400 13px/1.4 var(--au-font-sans);
  margin: 0;
}

.au-quote-preview__dismiss {
  --au-btn-height: 28px;
  --au-btn-padding-inline: 0;
  aspect-ratio: 1;
  min-width: 28px;
  width: 28px;
}

.au-quote-block {
  background: color-mix(in srgb, var(--au-fg) 4%, transparent);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-muted);
  font: italic 400 13px/1.45 var(--au-font-sans);
  margin: 0 0 8px;
  padding: 8px 12px;
}

.au-quote-toolbar {
  align-items: center;
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: inline-flex;
  gap: 2px;
  padding: 4px;
}
.au-quote-toolbar__btn {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg);
  cursor: pointer;
  display: inline-flex;
  font: 400 13px/1.3 var(--au-font-sans);
  gap: 8px;
  padding: 8px 12px;
}
.au-quote-toolbar__btn:hover,
.au-quote-toolbar__btn:focus-visible {
  background: var(--au-surface-muted);
  outline: 0;
}

/* --- absorbed: citation parts --- */
/* agent-ui / citation — first-class component (promoted from host extracts). */
/* Inline citations */
.au-citations {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 0;
}
.au-citation {
  background: var(--au-surface-muted);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 70%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  font: 400 12px/1.3 var(--au-font-sans);
  padding: 4px 8px;
  text-decoration: none;
}
.au-citation:hover,
.au-citation:focus-visible { color: var(--au-fg); outline: 0; }
.au-citation:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
.au-sources {
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  margin-top: 12px;
  padding: 8px 12px;
}
.au-sources > summary {
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 500 12px/1.3 var(--au-font-sans);
  list-style: none;
}
.au-sources > summary::-webkit-details-marker { display: none; }
.au-sources__list {
  display: grid;
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
}
.au-sources__item {
  color: var(--au-fg-muted);
  font: 400 12px/1.4 var(--au-font-sans);
}

/* --- absorbed: message-timing parts --- */
/* agent-ui / message-timing — first-class component (promoted from host extracts). */
/* Message timing badge + details panel (message-timing sample). */
.au-msg-timing { position: relative; }
.au-msg-timing__badge {
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  cursor: pointer;
  font: 400 12px/1 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
  list-style: none;
  padding: 8px;
}
.au-msg-timing__badge::-webkit-details-marker { display: none; }
.au-msg-timing__badge:hover,
.au-msg-timing[open] > .au-msg-timing__badge {
  background: var(--au-surface-muted);
  color: var(--au-fg);
}
.au-msg-timing__panel {
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: grid;
  gap: 8px;
  margin-top: 8px;
  min-width: 11rem;
  padding: 12px;
}
.au-msg-timing__row {
  display: flex;
  font: 400 12px/1.3 var(--au-font-sans);
  gap: 16px;
  justify-content: space-between;
}
.au-msg-timing__label { color: var(--au-fg-muted); }
.au-msg-timing__value {
  color: var(--au-fg);
  font: 400 12px/1.3 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
}

/* --- absorbed: follow-ups parts --- */
/* agent-ui / follow-ups — first-class component (promoted from host extracts). */
/* Post-reply follow-up chips (ThreadFollowupSuggestions). Host owns click → composer. */
.au-followups {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 0;
}
.au-followups__chip {
  background: var(--au-surface);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 60%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 400 13px/1.3 var(--au-font-sans);
  padding: 8px 12px;
  text-align: start;
}
@media (max-width: 640px) {
  .au-followups__chip,
  .au-quote-preview__dismiss,
  .au-quote-toolbar__btn,
  .au-msg-timing__badge,
  .au-sources > summary,
  .au-citation {
    min-height: 40px;
    min-width: 40px;
  }
}
.au-followups__chip:hover,
.au-followups__chip:focus-visible {
  background: var(--au-surface-muted);
  color: var(--au-fg);
  outline: 0;
}
.au-followups__chip:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
</style>

<blockquote class="au-quote-block">Selected user text for reply context.</blockquote>

Citations

chat-message / Citationsinteractive

Code

chat-message.html + chat-message.css
chat-message
<style>
.au-chat-message {
  --au-message-gap: 8px;
  --au-message-avatar: 28px;
  --au-message-max: min(70%, 36rem);
  display: flex;
  flex-direction: column;
  gap: var(--au-message-gap);
  width: 100%;
}

.au-chat-message__avatar {
  display: none;
}

.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  gap: 12px;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
}

.au-chat-message--with-avatar.au-chat-message__avatar {
  align-items: center;
  background: var(--au-surface-muted);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  display: flex;
  font: 600 10px/1 var(--au-font-sans);
  height: var(--au-message-avatar);
  justify-content: center;
  width: var(--au-message-avatar);
}

.au-chat-message__meta {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 2px;
}

.au-chat-message__role {
  color: var(--au-fg);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.au-chat-message__time,
.au-chat-message__model {
  color: var(--au-fg-subtle);
  font: 12px/1.3 var(--au-font-sans);
}

.au-chat-message__body {
  color: var(--au-fg);
  font-size: 16px;
  letter-spacing: -0.011em;
  line-height: 1.625;
  margin: 0;
  overflow-wrap: break-word;
}

.au-chat-message__body p + p {
  margin-top: 12px;
}

.au-chat-message__body code {
  background: var(--au-surface-muted);
  border-radius: var(--au-radius-xs);
  color: var(--au-fg);
  font: 0.85em/1.4 var(--au-font-mono);
  padding: 0.12em 0.35em 0.05em;
}

.au-chat-message__details {
  margin: 0;
}

.au-chat-message__details > summary {
  color: var(--au-fg-subtle);
  cursor: pointer;
  display: inline-flex;
  font: 12px/1.3 var(--au-font-sans);
  list-style: none;
  margin-bottom: 8px;
  width: fit-content;
}

.au-chat-message__details > summary::-webkit-details-marker {
  display: none;
}

.au-chat-message__details > summary:focus-visible {
  border-radius: var(--au-radius-sm);
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}

.au-chat-message__actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 8px;
  min-height: 32px;
  padding-top: 8px;
}

.au-chat-message__actions.au-btn {
  --au-btn-height: 24px;
  --au-btn-padding-inline: 8px;
  --au-btn-radius: var(--au-radius-md);
  color: var(--au-fg-muted);
  font: 500 12px/1 var(--au-font-sans);
  min-height: 24px;
}
.au-chat-message__actions.au-btn:hover:not(:disabled) { background: var(--au-surface-muted); color: var(--au-fg); }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: scale(0.9); }

.au-chat-message--assistant {
  padding-inline: 8px;
}

.au-chat-message--assistant.au-chat-message__meta {
  display: none;
}

.au-chat-message--user {
  align-items: flex-end;
  display: grid;
  grid-template-columns: minmax(72px, 1fr) auto;
  margin-inline-start: 0;
  padding-inline: 8px;
}

.au-chat-message--user > * {
  grid-column: 2;
}

.au-chat-message--user.au-chat-message__meta {
  display: none;
}

.au-chat-message--user.au-chat-message__body,
.au-chat-message--user.au-chat-message__details {
  background: var(--au-action);
  border-radius: var(--au-radius-lg);
  color: var(--au-action-fg);
  line-height: 1.5;
  max-width: var(--au-message-max);
  padding: 12px 16px;
  width: fit-content;
}

.au-chat-message--user.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
  margin-inline-start: 0;
}

.au-chat-message--user.au-chat-message--with-avatar > * {
  grid-column: auto;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__body,
.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__details {
  background: transparent;
  border-radius: 0;
  max-width: none;
  padding: 0;
}

.au-chat-message--assistant.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--system {
  padding-inline: 8px;
}

.au-chat-message--system.au-chat-message__body {
  color: var(--au-fg-subtle);
  font-size: 13px;
  line-height: 1.5;
}

.au-chat-message--tool {
  border-top: 1px solid var(--au-border-color);
  padding-inline: 8px;
  padding-top: 16px;
}

.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after {
  animation: au-message-caret 1s step-end infinite;
  background: var(--au-fg);
  content: "";
  display: inline-block;
  height: 1.05em;
  margin-inline-start: 2px;
  vertical-align: text-bottom;
  width: 2px;
}

@keyframes au-message-caret {
  50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after { animation: none; }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: none; }
}

/* --- absorbed: quote parts --- */
/* agent-ui / quote — first-class component (promoted from host extracts). */
/* base.tsx ComposerQuotePreview / QuoteBlock — host chrome (no side-tab accent) */
.au-quote-preview {
  align-items: flex-start;
  background: color-mix(in srgb, var(--au-fg) 5%, var(--au-surface));
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  display: flex;
  gap: 8px;
  margin-bottom: 4px;
  padding: 8px 12px;
}

.au-quote-preview__text {
  color: var(--au-fg-muted);
  flex: 1;
  font: 400 13px/1.4 var(--au-font-sans);
  margin: 0;
}

.au-quote-preview__dismiss {
  --au-btn-height: 28px;
  --au-btn-padding-inline: 0;
  aspect-ratio: 1;
  min-width: 28px;
  width: 28px;
}

.au-quote-block {
  background: color-mix(in srgb, var(--au-fg) 4%, transparent);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-muted);
  font: italic 400 13px/1.45 var(--au-font-sans);
  margin: 0 0 8px;
  padding: 8px 12px;
}

.au-quote-toolbar {
  align-items: center;
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: inline-flex;
  gap: 2px;
  padding: 4px;
}
.au-quote-toolbar__btn {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg);
  cursor: pointer;
  display: inline-flex;
  font: 400 13px/1.3 var(--au-font-sans);
  gap: 8px;
  padding: 8px 12px;
}
.au-quote-toolbar__btn:hover,
.au-quote-toolbar__btn:focus-visible {
  background: var(--au-surface-muted);
  outline: 0;
}

/* --- absorbed: citation parts --- */
/* agent-ui / citation — first-class component (promoted from host extracts). */
/* Inline citations */
.au-citations {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 0;
}
.au-citation {
  background: var(--au-surface-muted);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 70%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  font: 400 12px/1.3 var(--au-font-sans);
  padding: 4px 8px;
  text-decoration: none;
}
.au-citation:hover,
.au-citation:focus-visible { color: var(--au-fg); outline: 0; }
.au-citation:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
.au-sources {
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  margin-top: 12px;
  padding: 8px 12px;
}
.au-sources > summary {
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 500 12px/1.3 var(--au-font-sans);
  list-style: none;
}
.au-sources > summary::-webkit-details-marker { display: none; }
.au-sources__list {
  display: grid;
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
}
.au-sources__item {
  color: var(--au-fg-muted);
  font: 400 12px/1.4 var(--au-font-sans);
}

/* --- absorbed: message-timing parts --- */
/* agent-ui / message-timing — first-class component (promoted from host extracts). */
/* Message timing badge + details panel (message-timing sample). */
.au-msg-timing { position: relative; }
.au-msg-timing__badge {
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  cursor: pointer;
  font: 400 12px/1 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
  list-style: none;
  padding: 8px;
}
.au-msg-timing__badge::-webkit-details-marker { display: none; }
.au-msg-timing__badge:hover,
.au-msg-timing[open] > .au-msg-timing__badge {
  background: var(--au-surface-muted);
  color: var(--au-fg);
}
.au-msg-timing__panel {
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: grid;
  gap: 8px;
  margin-top: 8px;
  min-width: 11rem;
  padding: 12px;
}
.au-msg-timing__row {
  display: flex;
  font: 400 12px/1.3 var(--au-font-sans);
  gap: 16px;
  justify-content: space-between;
}
.au-msg-timing__label { color: var(--au-fg-muted); }
.au-msg-timing__value {
  color: var(--au-fg);
  font: 400 12px/1.3 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
}

/* --- absorbed: follow-ups parts --- */
/* agent-ui / follow-ups — first-class component (promoted from host extracts). */
/* Post-reply follow-up chips (ThreadFollowupSuggestions). Host owns click → composer. */
.au-followups {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 0;
}
.au-followups__chip {
  background: var(--au-surface);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 60%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 400 13px/1.3 var(--au-font-sans);
  padding: 8px 12px;
  text-align: start;
}
@media (max-width: 640px) {
  .au-followups__chip,
  .au-quote-preview__dismiss,
  .au-quote-toolbar__btn,
  .au-msg-timing__badge,
  .au-sources > summary,
  .au-citation {
    min-height: 40px;
    min-width: 40px;
  }
}
.au-followups__chip:hover,
.au-followups__chip:focus-visible {
  background: var(--au-surface-muted);
  color: var(--au-fg);
  outline: 0;
}
.au-followups__chip:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
</style>

<div class="au-citations"><a class="au-citation" href="#src-1">Source 1</a><a class="au-citation" href="#src-2">Source 2</a></div>

Timing

chat-message / Timinginteractive
1.2s
TTFT320ms

Code

chat-message.html + chat-message.css
chat-message
<style>
.au-chat-message {
  --au-message-gap: 8px;
  --au-message-avatar: 28px;
  --au-message-max: min(70%, 36rem);
  display: flex;
  flex-direction: column;
  gap: var(--au-message-gap);
  width: 100%;
}

.au-chat-message__avatar {
  display: none;
}

.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  gap: 12px;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
}

.au-chat-message--with-avatar.au-chat-message__avatar {
  align-items: center;
  background: var(--au-surface-muted);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  display: flex;
  font: 600 10px/1 var(--au-font-sans);
  height: var(--au-message-avatar);
  justify-content: center;
  width: var(--au-message-avatar);
}

.au-chat-message__meta {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 2px;
}

.au-chat-message__role {
  color: var(--au-fg);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.au-chat-message__time,
.au-chat-message__model {
  color: var(--au-fg-subtle);
  font: 12px/1.3 var(--au-font-sans);
}

.au-chat-message__body {
  color: var(--au-fg);
  font-size: 16px;
  letter-spacing: -0.011em;
  line-height: 1.625;
  margin: 0;
  overflow-wrap: break-word;
}

.au-chat-message__body p + p {
  margin-top: 12px;
}

.au-chat-message__body code {
  background: var(--au-surface-muted);
  border-radius: var(--au-radius-xs);
  color: var(--au-fg);
  font: 0.85em/1.4 var(--au-font-mono);
  padding: 0.12em 0.35em 0.05em;
}

.au-chat-message__details {
  margin: 0;
}

.au-chat-message__details > summary {
  color: var(--au-fg-subtle);
  cursor: pointer;
  display: inline-flex;
  font: 12px/1.3 var(--au-font-sans);
  list-style: none;
  margin-bottom: 8px;
  width: fit-content;
}

.au-chat-message__details > summary::-webkit-details-marker {
  display: none;
}

.au-chat-message__details > summary:focus-visible {
  border-radius: var(--au-radius-sm);
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}

.au-chat-message__actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 8px;
  min-height: 32px;
  padding-top: 8px;
}

.au-chat-message__actions.au-btn {
  --au-btn-height: 24px;
  --au-btn-padding-inline: 8px;
  --au-btn-radius: var(--au-radius-md);
  color: var(--au-fg-muted);
  font: 500 12px/1 var(--au-font-sans);
  min-height: 24px;
}
.au-chat-message__actions.au-btn:hover:not(:disabled) { background: var(--au-surface-muted); color: var(--au-fg); }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: scale(0.9); }

.au-chat-message--assistant {
  padding-inline: 8px;
}

.au-chat-message--assistant.au-chat-message__meta {
  display: none;
}

.au-chat-message--user {
  align-items: flex-end;
  display: grid;
  grid-template-columns: minmax(72px, 1fr) auto;
  margin-inline-start: 0;
  padding-inline: 8px;
}

.au-chat-message--user > * {
  grid-column: 2;
}

.au-chat-message--user.au-chat-message__meta {
  display: none;
}

.au-chat-message--user.au-chat-message__body,
.au-chat-message--user.au-chat-message__details {
  background: var(--au-action);
  border-radius: var(--au-radius-lg);
  color: var(--au-action-fg);
  line-height: 1.5;
  max-width: var(--au-message-max);
  padding: 12px 16px;
  width: fit-content;
}

.au-chat-message--user.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
  margin-inline-start: 0;
}

.au-chat-message--user.au-chat-message--with-avatar > * {
  grid-column: auto;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__body,
.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__details {
  background: transparent;
  border-radius: 0;
  max-width: none;
  padding: 0;
}

.au-chat-message--assistant.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--system {
  padding-inline: 8px;
}

.au-chat-message--system.au-chat-message__body {
  color: var(--au-fg-subtle);
  font-size: 13px;
  line-height: 1.5;
}

.au-chat-message--tool {
  border-top: 1px solid var(--au-border-color);
  padding-inline: 8px;
  padding-top: 16px;
}

.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after {
  animation: au-message-caret 1s step-end infinite;
  background: var(--au-fg);
  content: "";
  display: inline-block;
  height: 1.05em;
  margin-inline-start: 2px;
  vertical-align: text-bottom;
  width: 2px;
}

@keyframes au-message-caret {
  50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after { animation: none; }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: none; }
}

/* --- absorbed: quote parts --- */
/* agent-ui / quote — first-class component (promoted from host extracts). */
/* base.tsx ComposerQuotePreview / QuoteBlock — host chrome (no side-tab accent) */
.au-quote-preview {
  align-items: flex-start;
  background: color-mix(in srgb, var(--au-fg) 5%, var(--au-surface));
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  display: flex;
  gap: 8px;
  margin-bottom: 4px;
  padding: 8px 12px;
}

.au-quote-preview__text {
  color: var(--au-fg-muted);
  flex: 1;
  font: 400 13px/1.4 var(--au-font-sans);
  margin: 0;
}

.au-quote-preview__dismiss {
  --au-btn-height: 28px;
  --au-btn-padding-inline: 0;
  aspect-ratio: 1;
  min-width: 28px;
  width: 28px;
}

.au-quote-block {
  background: color-mix(in srgb, var(--au-fg) 4%, transparent);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-muted);
  font: italic 400 13px/1.45 var(--au-font-sans);
  margin: 0 0 8px;
  padding: 8px 12px;
}

.au-quote-toolbar {
  align-items: center;
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: inline-flex;
  gap: 2px;
  padding: 4px;
}
.au-quote-toolbar__btn {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg);
  cursor: pointer;
  display: inline-flex;
  font: 400 13px/1.3 var(--au-font-sans);
  gap: 8px;
  padding: 8px 12px;
}
.au-quote-toolbar__btn:hover,
.au-quote-toolbar__btn:focus-visible {
  background: var(--au-surface-muted);
  outline: 0;
}

/* --- absorbed: citation parts --- */
/* agent-ui / citation — first-class component (promoted from host extracts). */
/* Inline citations */
.au-citations {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 0;
}
.au-citation {
  background: var(--au-surface-muted);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 70%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  font: 400 12px/1.3 var(--au-font-sans);
  padding: 4px 8px;
  text-decoration: none;
}
.au-citation:hover,
.au-citation:focus-visible { color: var(--au-fg); outline: 0; }
.au-citation:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
.au-sources {
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  margin-top: 12px;
  padding: 8px 12px;
}
.au-sources > summary {
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 500 12px/1.3 var(--au-font-sans);
  list-style: none;
}
.au-sources > summary::-webkit-details-marker { display: none; }
.au-sources__list {
  display: grid;
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
}
.au-sources__item {
  color: var(--au-fg-muted);
  font: 400 12px/1.4 var(--au-font-sans);
}

/* --- absorbed: message-timing parts --- */
/* agent-ui / message-timing — first-class component (promoted from host extracts). */
/* Message timing badge + details panel (message-timing sample). */
.au-msg-timing { position: relative; }
.au-msg-timing__badge {
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  cursor: pointer;
  font: 400 12px/1 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
  list-style: none;
  padding: 8px;
}
.au-msg-timing__badge::-webkit-details-marker { display: none; }
.au-msg-timing__badge:hover,
.au-msg-timing[open] > .au-msg-timing__badge {
  background: var(--au-surface-muted);
  color: var(--au-fg);
}
.au-msg-timing__panel {
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: grid;
  gap: 8px;
  margin-top: 8px;
  min-width: 11rem;
  padding: 12px;
}
.au-msg-timing__row {
  display: flex;
  font: 400 12px/1.3 var(--au-font-sans);
  gap: 16px;
  justify-content: space-between;
}
.au-msg-timing__label { color: var(--au-fg-muted); }
.au-msg-timing__value {
  color: var(--au-fg);
  font: 400 12px/1.3 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
}

/* --- absorbed: follow-ups parts --- */
/* agent-ui / follow-ups — first-class component (promoted from host extracts). */
/* Post-reply follow-up chips (ThreadFollowupSuggestions). Host owns click → composer. */
.au-followups {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 0;
}
.au-followups__chip {
  background: var(--au-surface);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 60%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 400 13px/1.3 var(--au-font-sans);
  padding: 8px 12px;
  text-align: start;
}
@media (max-width: 640px) {
  .au-followups__chip,
  .au-quote-preview__dismiss,
  .au-quote-toolbar__btn,
  .au-msg-timing__badge,
  .au-sources > summary,
  .au-citation {
    min-height: 40px;
    min-width: 40px;
  }
}
.au-followups__chip:hover,
.au-followups__chip:focus-visible {
  background: var(--au-surface-muted);
  color: var(--au-fg);
  outline: 0;
}
.au-followups__chip:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
</style>

<details class="au-msg-timing"><summary class="au-msg-timing__badge">1.2s</summary><div class="au-msg-timing__panel"><div class="au-msg-timing__row"><span class="au-msg-timing__label">TTFT</span><span class="au-msg-timing__value">320ms</span></div></div></details>

Follow-ups

chat-message / Follow-upsinteractive

Code

chat-message.html + chat-message.css
chat-message
<style>
.au-chat-message {
  --au-message-gap: 8px;
  --au-message-avatar: 28px;
  --au-message-max: min(70%, 36rem);
  display: flex;
  flex-direction: column;
  gap: var(--au-message-gap);
  width: 100%;
}

.au-chat-message__avatar {
  display: none;
}

.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  gap: 12px;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
}

.au-chat-message--with-avatar.au-chat-message__avatar {
  align-items: center;
  background: var(--au-surface-muted);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  display: flex;
  font: 600 10px/1 var(--au-font-sans);
  height: var(--au-message-avatar);
  justify-content: center;
  width: var(--au-message-avatar);
}

.au-chat-message__meta {
  align-items: baseline;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 2px;
}

.au-chat-message__role {
  color: var(--au-fg);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

.au-chat-message__time,
.au-chat-message__model {
  color: var(--au-fg-subtle);
  font: 12px/1.3 var(--au-font-sans);
}

.au-chat-message__body {
  color: var(--au-fg);
  font-size: 16px;
  letter-spacing: -0.011em;
  line-height: 1.625;
  margin: 0;
  overflow-wrap: break-word;
}

.au-chat-message__body p + p {
  margin-top: 12px;
}

.au-chat-message__body code {
  background: var(--au-surface-muted);
  border-radius: var(--au-radius-xs);
  color: var(--au-fg);
  font: 0.85em/1.4 var(--au-font-mono);
  padding: 0.12em 0.35em 0.05em;
}

.au-chat-message__details {
  margin: 0;
}

.au-chat-message__details > summary {
  color: var(--au-fg-subtle);
  cursor: pointer;
  display: inline-flex;
  font: 12px/1.3 var(--au-font-sans);
  list-style: none;
  margin-bottom: 8px;
  width: fit-content;
}

.au-chat-message__details > summary::-webkit-details-marker {
  display: none;
}

.au-chat-message__details > summary:focus-visible {
  border-radius: var(--au-radius-sm);
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}

.au-chat-message__actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 8px;
  min-height: 32px;
  padding-top: 8px;
}

.au-chat-message__actions.au-btn {
  --au-btn-height: 24px;
  --au-btn-padding-inline: 8px;
  --au-btn-radius: var(--au-radius-md);
  color: var(--au-fg-muted);
  font: 500 12px/1 var(--au-font-sans);
  min-height: 24px;
}
.au-chat-message__actions.au-btn:hover:not(:disabled) { background: var(--au-surface-muted); color: var(--au-fg); }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: scale(0.9); }

.au-chat-message--assistant {
  padding-inline: 8px;
}

.au-chat-message--assistant.au-chat-message__meta {
  display: none;
}

.au-chat-message--user {
  align-items: flex-end;
  display: grid;
  grid-template-columns: minmax(72px, 1fr) auto;
  margin-inline-start: 0;
  padding-inline: 8px;
}

.au-chat-message--user > * {
  grid-column: 2;
}

.au-chat-message--user.au-chat-message__meta {
  display: none;
}

.au-chat-message--user.au-chat-message__body,
.au-chat-message--user.au-chat-message__details {
  background: var(--au-action);
  border-radius: var(--au-radius-lg);
  color: var(--au-action-fg);
  line-height: 1.5;
  max-width: var(--au-message-max);
  padding: 12px 16px;
  width: fit-content;
}

.au-chat-message--user.au-chat-message--with-avatar {
  align-items: start;
  display: grid;
  grid-template-columns: var(--au-message-avatar) minmax(0, 1fr);
  margin-inline-start: 0;
}

.au-chat-message--user.au-chat-message--with-avatar > * {
  grid-column: auto;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__body,
.au-chat-message--user.au-chat-message--with-avatar.au-chat-message__details {
  background: transparent;
  border-radius: 0;
  max-width: none;
  padding: 0;
}

.au-chat-message--assistant.au-chat-message--with-avatar.au-chat-message__meta {
  display: flex;
}

.au-chat-message--system {
  padding-inline: 8px;
}

.au-chat-message--system.au-chat-message__body {
  color: var(--au-fg-subtle);
  font-size: 13px;
  line-height: 1.5;
}

.au-chat-message--tool {
  border-top: 1px solid var(--au-border-color);
  padding-inline: 8px;
  padding-top: 16px;
}

.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after {
  animation: au-message-caret 1s step-end infinite;
  background: var(--au-fg);
  content: "";
  display: inline-block;
  height: 1.05em;
  margin-inline-start: 2px;
  vertical-align: text-bottom;
  width: 2px;
}

@keyframes au-message-caret {
  50% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
.au-chat-message[data-au-state="streaming"] .au-chat-message__body::after { animation: none; }
.au-chat-message__actions.au-btn:active:not(:disabled) { transform: none; }
}

/* --- absorbed: quote parts --- */
/* agent-ui / quote — first-class component (promoted from host extracts). */
/* base.tsx ComposerQuotePreview / QuoteBlock — host chrome (no side-tab accent) */
.au-quote-preview {
  align-items: flex-start;
  background: color-mix(in srgb, var(--au-fg) 5%, var(--au-surface));
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  display: flex;
  gap: 8px;
  margin-bottom: 4px;
  padding: 8px 12px;
}

.au-quote-preview__text {
  color: var(--au-fg-muted);
  flex: 1;
  font: 400 13px/1.4 var(--au-font-sans);
  margin: 0;
}

.au-quote-preview__dismiss {
  --au-btn-height: 28px;
  --au-btn-padding-inline: 0;
  aspect-ratio: 1;
  min-width: 28px;
  width: 28px;
}

.au-quote-block {
  background: color-mix(in srgb, var(--au-fg) 4%, transparent);
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-muted);
  font: italic 400 13px/1.45 var(--au-font-sans);
  margin: 0 0 8px;
  padding: 8px 12px;
}

.au-quote-toolbar {
  align-items: center;
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: inline-flex;
  gap: 2px;
  padding: 4px;
}
.au-quote-toolbar__btn {
  align-items: center;
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg);
  cursor: pointer;
  display: inline-flex;
  font: 400 13px/1.3 var(--au-font-sans);
  gap: 8px;
  padding: 8px 12px;
}
.au-quote-toolbar__btn:hover,
.au-quote-toolbar__btn:focus-visible {
  background: var(--au-surface-muted);
  outline: 0;
}

/* --- absorbed: citation parts --- */
/* agent-ui / citation — first-class component (promoted from host extracts). */
/* Inline citations */
.au-citations {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 8px 0 0;
}
.au-citation {
  background: var(--au-surface-muted);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 70%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  font: 400 12px/1.3 var(--au-font-sans);
  padding: 4px 8px;
  text-decoration: none;
}
.au-citation:hover,
.au-citation:focus-visible { color: var(--au-fg); outline: 0; }
.au-citation:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
.au-sources {
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  margin-top: 12px;
  padding: 8px 12px;
}
.au-sources > summary {
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 500 12px/1.3 var(--au-font-sans);
  list-style: none;
}
.au-sources > summary::-webkit-details-marker { display: none; }
.au-sources__list {
  display: grid;
  gap: 8px;
  margin: 8px 0 0;
  padding: 0;
}
.au-sources__item {
  color: var(--au-fg-muted);
  font: 400 12px/1.4 var(--au-font-sans);
}

/* --- absorbed: message-timing parts --- */
/* agent-ui / message-timing — first-class component (promoted from host extracts). */
/* Message timing badge + details panel (message-timing sample). */
.au-msg-timing { position: relative; }
.au-msg-timing__badge {
  background: transparent;
  border: 0;
  border-radius: var(--au-radius-sm);
  color: var(--au-fg-subtle);
  cursor: pointer;
  font: 400 12px/1 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
  list-style: none;
  padding: 8px;
}
.au-msg-timing__badge::-webkit-details-marker { display: none; }
.au-msg-timing__badge:hover,
.au-msg-timing[open] > .au-msg-timing__badge {
  background: var(--au-surface-muted);
  color: var(--au-fg);
}
.au-msg-timing__panel {
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-md);
  box-shadow: 0 2px 8px color-mix(in srgb, var(--au-fg) 8%, transparent);
  display: grid;
  gap: 8px;
  margin-top: 8px;
  min-width: 11rem;
  padding: 12px;
}
.au-msg-timing__row {
  display: flex;
  font: 400 12px/1.3 var(--au-font-sans);
  gap: 16px;
  justify-content: space-between;
}
.au-msg-timing__label { color: var(--au-fg-muted); }
.au-msg-timing__value {
  color: var(--au-fg);
  font: 400 12px/1.3 var(--au-font-mono);
  font-variant-numeric: tabular-nums;
}

/* --- absorbed: follow-ups parts --- */
/* agent-ui / follow-ups — first-class component (promoted from host extracts). */
/* Post-reply follow-up chips (ThreadFollowupSuggestions). Host owns click → composer. */
.au-followups {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0 0;
}
.au-followups__chip {
  background: var(--au-surface);
  border: 1px solid color-mix(in srgb, var(--au-border-color) 60%, transparent);
  border-radius: var(--au-radius-pill);
  color: var(--au-fg-muted);
  cursor: pointer;
  font: 400 13px/1.3 var(--au-font-sans);
  padding: 8px 12px;
  text-align: start;
}
@media (max-width: 640px) {
  .au-followups__chip,
  .au-quote-preview__dismiss,
  .au-quote-toolbar__btn,
  .au-msg-timing__badge,
  .au-sources > summary,
  .au-citation {
    min-height: 40px;
    min-width: 40px;
  }
}
.au-followups__chip:hover,
.au-followups__chip:focus-visible {
  background: var(--au-surface-muted);
  color: var(--au-fg);
  outline: 0;
}
.au-followups__chip:focus-visible {
  box-shadow: var(--au-focus-ring);
  outline: 2px solid var(--au-focus);
  outline-offset: 2px;
}
</style>

<div class="au-followups"><button type="button" class="au-followups__chip" data-au-prompt="Show details">Show details</button></div>

Component contract

Install
tokens.css · chat-message.css · button.css · recipes/chat-message-prose.css
States
idle, streaming, success, error, cancelled
Host
identity, streaming, actions, and part visibility
For agents
chat-message.contract
# agent-ui / chat-message
component: chat-message
selector: .au-chat-message
data_au_component: chat-message
purpose: Turn chrome with optional quote, citation, timing, and follow-up parts.

install:
  - tokens.css
  - chat-message.css
  - button.css for actions
  - recipes/chat-message-prose.css optional

states: idle, streaming, success, error, cancelled.
css_variables: Uses message gap and max-width tokens.
events: native form, focus, and click only — no custom events or runtime required
no_javascript: Article and native details remain usable.
host_owns: The host owns identity, streaming, actions, and part visibility.
accessibility: Expose role/time as text; actions need labels.
security: Escape body, quotes, citations, and follow-up prompts.

rules:
  - Host owns execution, authorization, persistence, validation, and state transitions.
  - Components render host-provided state; they never execute tools or imply approval.
  - Escape untrusted model output, tool args, and tool output before insertion.
  - Use only documented data-au-* attributes and data-au-state values.
  - Keep the no-JS path usable. Do not add React, Tailwind, bundlers, or remote assets.
source: components/chat-message/chat-message.{html,css} + README.md + fixture.html