Explain React hooks like useState
Installation
tokens.css + chat-message.css + button.css + recipes/chat-message-prose.csshead.html
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="components/chat-message/chat-message.css">Basic
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
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
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
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
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