recipe / 01

Specimen

Preview the live recipe, then copy HTML or Install. CSS is composition-only: copy the listed component stylesheets.

Preview

live-run / release notesstreaming / waiting for tokens
Human

Summarize the latest changes and keep the draft editable.

Agent

I am still assembling the release note...

Agent is thinking
Read the repository
Write the summary
System

The host decides when a stream is complete. The component never invents success.

Code

chat-streaming.html
<section class="au-chat-thread" aria-label="Streaming conversation">
  <div class="au-chat-thread__messages">
    <article class="au-chat-message au-chat-message--user">
      <span class="au-chat-message__avatar" aria-hidden="true">you</span>
      <div>
        <div class="au-chat-message__meta"><span class="au-chat-message__role">Human</span><time class="au-chat-message__time">09:41</time></div>
        <p class="au-chat-message__body">Summarize the latest changes and keep the draft editable.</p>
      </div>
    </article>
    <article class="au-chat-message au-chat-message--assistant" data-au-state="streaming">
      <span class="au-chat-message__avatar" aria-hidden="true">au</span>
      <div>
        <div class="au-chat-message__meta"><span class="au-chat-message__role">Agent</span><time class="au-chat-message__time">09:42</time></div>
        <p class="au-chat-message__body">I am still assembling the release note...</p>
        <div class="au-thinking-indicator" role="status" aria-live="polite"><span class="au-thinking-indicator__dots" aria-hidden="true"><span></span><span></span><span></span></span><span class="au-thinking-indicator__label">Agent is thinking</span></div>
      </div>
    </article>
  </div>
  <div class="au-chat-thread__composer">
    <form class="au-chat-input" method="post">
      <label class="sr-only" for="stream-message">Message</label>
      <textarea class="au-chat-input__textarea" id="stream-message" name="message" rows="2" placeholder="Ask the agent to continue..."></textarea>
      <div class="au-chat-input__footer"><span class="au-chat-input__hint">Native form, host-owned submit.</span><button class="au-btn au-btn--primary" type="submit">Send</button></div>
    </form>
  </div>
</section>
Composition only — copy component CSS from chat-thread, chat-message, chat-input, thinking-indicator, and thinking-steps. Do not treat recipes.css as product CSS.

Install

head.html
<link rel="stylesheet" href="tokens.css">
<link rel="stylesheet" href="components/button/button.css">
<link rel="stylesheet" href="components/chat-thread/chat-thread.css">
<link rel="stylesheet" href="components/chat-message/chat-message.css">
<link rel="stylesheet" href="components/chat-input/chat-input.css">
<link rel="stylesheet" href="components/thinking-indicator/thinking-indicator.css">
<link rel="stylesheet" href="components/thinking-steps/thinking-steps.css">
<link rel="stylesheet" href="host-chrome.css">

Static state matrix

visible without JavaScript

The host can pre-render any terminal state. Keep the message body and status label together so a refresh never loses the explanation.

streaming tokens still arriving

Agent

Drafting the final paragraph...

success complete response

Agent

The release note draft is complete.

error recoverable interruption

Agent

The stream stopped. Retry from the last saved token.

cancelled host stopped run

Agent

The host cancelled this response before completion.

Contract and safety

Install
tokens.css, chat-thread.css, chat-message.css, chat-input.css, thinking-indicator.css, and thinking-steps.css.
States
streaming, success, error, and cancelled are host-rendered on the message.
No JavaScript
Messages, elapsed steps, the partial response, and the native composer remain visible in document flow.
Accessibility
Use an article, expose the role as text, label the thread, announce status politely, and keep the thinking dots decorative.
Security
Streamed text is untrusted content. Escape it before insertion and never interpret it as HTML.
Host boundary
The host owns token buffering, retry, cancellation, persistence, and the decision that a response is complete.

Source map

The smallest copyable flow is split across independent primitives. Replace the demo controller with the host's stream events.