Gallery

Live demos

Working examples, built as real DOM. Tab through them, run a screen reader over them, zoom in, or switch on reduced motion and see what changes.

The agents here are canned. Nothing calls a model, and the same request always gets the same answer.

A minimal accessible chat

Demonstrates Announced State Changes, Stall Signal, Stop Control, Scroll Stays Put, Durable Errors, Speaker Labels, Semantic Rendering, Reflowable Output, Focus Stays Put, Actions on Focus and Forgiving Composer.

Conversation

  1. Assistant

    Hi. I can look up your accounts and contribution limits. What would you like to know?

Ready.

Enter sends. Shift+Enter adds a line. Escape stops a response.

Simulate

Try this with a screen reader on: press Send and keep your focus in the message box. You'll hear "Assistant is responding", the steps, and then "Response complete" once. The streaming text is not a live region, so it isn't read chunk by chunk. When you want the answer, use "Go to latest response" or jump by heading.

Then try breaking it: scroll up mid-response (the view stays where you put it), press Escape to stop (the partial answer stays), turn on "The next send fails" (the error stays on the page and your text stays in the box), or zoom to 400% (the table scrolls inside its own box, not the page).

An approval that waits for you

Demonstrates Reachable Approval, Untimed Approval and Reversible by Default.

Idle.

    Try this: run the agent and keep your focus on the Run button. When the agent pauses, the status line announces what it's waiting for and a "Go to approval" button appears. Focus doesn't jump on its own. The approval has no countdown, the buttons say what they do, and a completed transfer can be undone.

    What most products ship instead: a card titled "Confirm action", buttons labeled "Confirm" and "Cancel", and "Proceeding in 10 seconds" underneath.

    Announced progress, readable result

    Demonstrates Announced State Changes, Post-Stream Readability and Reduced-Motion Streaming.

    Idle.

    Try this: start the run, then look away. The status line is a live region, so a screen reader announces "Working", then "Done", without you watching. When the run finishes, the full response stays on the page, readable from the top, because nothing here depends on having seen it arrive. If your system is set to reduced motion, the response renders in one pass instead of typing itself out.

    A trail you can operate

    Demonstrates Keyboard-Reachable Steps, Semantic Activity Trail and Status Beyond Color.

    Activity trail

    1. ReadRetrieved account balances

      accounts.list(owner: current_user) → 3 accounts as of 4:02pm

    2. ReadChecked 2026 contribution limit

      policy.lookup("ira_limit", year: 2026) → $7,500 source: plan document, rev. Jan 2026

    3. ReadCalculated remaining room

      7500 − 4100 = 3400

    4. WriteDrafted a contribution of $3,400

      draft.create(amount: 3400, status: "pending_approval"). Nothing moves until you approve.

    Try this: tab into the trail and press Enter or Space on a step. Each one is a real <details> element inside an ordered list, so it works from the keyboard, announces its expanded state, and can be skipped with list navigation. The one step that changes something is marked as a write in its text label as well as its border, so it doesn't read as a fourth identical lookup.

    Status that survives without color

    Demonstrates Status Beyond Color and Spoken Uncertainty.

    1. ReadLocated the joint brokerage account

      accounts.get(id: "…4471") → found

    2. BlockedStopped before placing the trade

      guardrail: trading_permissions. This session is read-only for joint accounts.

    Result I can't place trades in the joint account from here, because this session has read-only access to accounts you share. I can show you the order and what it would cost, or you can enable trading for this session in Settings and ask me again.

    Try this: switch between the two, ideally with a screen reader or a Windows contrast theme on. In the second version the only sign that a step was blocked is a red border, which isn't there for a screen reader, is hard to see with some color vision deficiencies, and disappears in forced-colors mode. The result gives the user nothing to do next. In the first, "Blocked" is text and the result names the boundary and two ways forward.