conversation / 05

Installation

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

Basic

chat-thread / Basicinteractive
Keep the draft editable

Keep the draft editable while the agent works.

The conversation remains in normal document flow.

Code

chat-thread.html + chat-thread.css
chat-thread
<style>
.au-chat-thread {
  --au-thread-bg: var(--au-bg);
  --au-thread-border: transparent;
  --au-thread-max-width: var(--au-thread-max, 44rem);
  background: var(--au-thread-bg);
  border: 0;
  border-radius: 0;
  display: flex;
  flex-direction: column;
  min-height: 420px;
  overflow: hidden;
}

.au-chat-thread__messages {
  display: flex;
  flex-direction: column;
  gap: 24px;
  margin-inline: auto;
  max-width: var(--au-thread-max-width);
  min-height: 0;
  overflow: auto;
  padding: 16px 16px 56px;
  scroll-behavior: smooth;
  width: 100%;
}

.au-chat-thread__composer {
  background: linear-gradient(to top, var(--au-bg) 70%, color-mix(in srgb, var(--au-bg) 0%, transparent));
  border-top: 0;
  margin-inline: auto;
  max-width: var(--au-thread-max-width);
  padding: 0 16px 16px;
  width: 100%;
}

.au-chat-thread__new {
  align-self: center;
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-pill);
  box-shadow: var(--au-elevation-composer);
  color: var(--au-fg-muted);
  font: 600 12px/1 var(--au-font-sans);
  margin-bottom: var(--au-space-3);
  padding: 8px 12px;
}

/* --- absorbed: tabs variant --- */
/* agent-ui / chat-tabs — first-class component (promoted from host extracts). */
/* 07 Chat tabs */
.au-chat-tabs { display: flex; gap: 4px; margin: 0 0 12px; }
.au-chat-tabs__tab[aria-pressed="true"] {
  background: var(--au-surface-muted);
  color: var(--au-fg);
}
.au-chat-tabs__panel[hidden] { display: none; }
</style>

<section class="au-chat-thread" aria-label="Preview conversation"><header class="au-chat-header"><button type="button" class="au-btn au-btn--ghost au-chat-header__icon au-chat-header__menu" aria-label="Toggle menu"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M4 5h16"/><path d="M4 12h16"/><path d="M4 19h16"/></svg></button><button type="button" class="au-btn au-btn--ghost au-chat-header__icon au-chat-header__sidebar" aria-label="Hide sidebar"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect width="18" height="18" x="3" y="3" rx="2"/><path d="M9 3v18"/></svg></button><span class="au-chat-header__title">Keep the draft editable</span><button type="button" class="au-btn au-btn--ghost au-chat-header__icon au-chat-header__share" aria-label="Share" disabled><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 2v13"/><path d="m16 6-4-4-4 4"/><path d="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8"/></svg></button></header><div class="au-chat-thread__messages"><article class="au-chat-message au-chat-message--user"><p class="au-chat-message__body">Keep the draft editable while the agent works.</p></article><article class="au-chat-message au-chat-message--assistant"><p class="au-chat-message__body">The conversation remains in normal document flow.</p></article></div><div class="au-chat-thread__composer"><form class="au-chat-input" method="post" aria-label="Message"><textarea class="au-chat-input__textarea" id="thread-preview-message" name="message" rows="1" placeholder="Send a message..." aria-label="Message"></textarea><div class="au-chat-input__footer"><span class="au-chat-input__hint">Native form</span><button class="au-btn au-btn--primary" type="submit" aria-label="Send">↑</button></div></form></div></section>

Tabs

chat-thread / Tabsinteractive

Code

chat-thread.html + chat-thread.css
chat-thread
<style>
.au-chat-thread {
  --au-thread-bg: var(--au-bg);
  --au-thread-border: transparent;
  --au-thread-max-width: var(--au-thread-max, 44rem);
  background: var(--au-thread-bg);
  border: 0;
  border-radius: 0;
  display: flex;
  flex-direction: column;
  min-height: 420px;
  overflow: hidden;
}

.au-chat-thread__messages {
  display: flex;
  flex-direction: column;
  gap: 24px;
  margin-inline: auto;
  max-width: var(--au-thread-max-width);
  min-height: 0;
  overflow: auto;
  padding: 16px 16px 56px;
  scroll-behavior: smooth;
  width: 100%;
}

.au-chat-thread__composer {
  background: linear-gradient(to top, var(--au-bg) 70%, color-mix(in srgb, var(--au-bg) 0%, transparent));
  border-top: 0;
  margin-inline: auto;
  max-width: var(--au-thread-max-width);
  padding: 0 16px 16px;
  width: 100%;
}

.au-chat-thread__new {
  align-self: center;
  background: var(--au-surface);
  border: 1px solid var(--au-border-color);
  border-radius: var(--au-radius-pill);
  box-shadow: var(--au-elevation-composer);
  color: var(--au-fg-muted);
  font: 600 12px/1 var(--au-font-sans);
  margin-bottom: var(--au-space-3);
  padding: 8px 12px;
}

/* --- absorbed: tabs variant --- */
/* agent-ui / chat-tabs — first-class component (promoted from host extracts). */
/* 07 Chat tabs */
.au-chat-tabs { display: flex; gap: 4px; margin: 0 0 12px; }
.au-chat-tabs__tab[aria-pressed="true"] {
  background: var(--au-surface-muted);
  color: var(--au-fg);
}
.au-chat-tabs__panel[hidden] { display: none; }
</style>

<div class="au-chat-tabs" data-au-component="chat-thread" data-au-variant="tabs" role="tablist"><button type="button" class="au-btn au-btn--ghost au-btn--sm au-chat-tabs__tab" aria-pressed="true">Chat</button><button type="button" class="au-btn au-btn--ghost au-btn--sm au-chat-tabs__tab" aria-pressed="false">Context</button></div>

Component contract

Install
tokens.css · chat-thread.css · chat-message.css · chat-input.css · button.css
States
static, streaming, new-content; tabs via variant parts
Host
scroll, insertion, persistence, and tab switching
For agents
chat-thread.contract
# agent-ui / chat-thread
component: chat-thread
selector: .au-chat-thread
data_au_component: chat-thread
purpose: Conversation scroll + composer slot, with optional tabs variant (absorbed chat-tabs).

install:
  - tokens.css
  - chat-thread.css
  - chat-message.css
  - chat-input.css
  - button.css

states: static, streaming, new-content; tabs via variant parts.
css_variables: Uses thread surface tokens.
events: native form, focus, and click only — no custom events or runtime required
no_javascript: Messages stay readable; nested forms can submit.
host_owns: The host owns scroll, insertion, persistence, and tab switching.
accessibility: Keep messages in a readable region; tabs need pressed/selected text.
security: Thread content is host-owned escaped text.

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-thread/chat-thread.{html,css} + README.md + fixture.html