## Canonical hierarchy

For the full live demo + state-as-attribute documentation, see /site/components/chat-shell. This page is the pattern hub.

<chat-shell provider="anthropic" model="claude-sonnet-4-7" proxy-url="/api/llm"> <!-- Header — name + status indicator --> <chat-header> <span slot="name">Claude</span> <chat-status slot="status">Connected</chat-status> </chat-header> <!-- Streaming message thread (with optional empty state) --> <chat-thread> <chat-empty> <empty-state-ui icon="chat-circle" heading="Hello!" description="Ask me anything."></empty-state-ui> </chat-empty> </chat-thread> <!-- Composer wraps the input primitive --> <chat-composer> <chat-input-ui placeholder="Message…"></chat-input-ui> </chat-composer> </chat-shell>

## Part-by-part reference

Part | Role
--- | ---
`<chat-shell>` | Behavior-only host. Wires LLM streaming, markdown rendering, code-block upgrades, the `proxy-url` integration path.
`<chat-header>` | Top band — slots: `name`, `status`, `action`.
`<chat-thread>` | Streaming message list. Reflects `[streaming]`.
`<chat-empty>` | Empty-state hint inside `<chat-thread>` before the first message.
`<chat-composer>` | Input area. Wraps `<chat-input-ui>`.
`<chat-sidebar>` | Optional conversation-list / inspector rail (`slot="leading"` or `slot="trailing"`).

## With sidebar — conversation list

For a multi-conversation surface, add a `<chat-sidebar slot="leading">` with a `<nav-ui>` of past chats.

<chat-shell> <chat-sidebar slot="leading"> <chat-topbar slot="header"> <span slot="heading">Conversations</span> <button-ui slot="action" text="+ New" variant="primary" size="sm"></button-ui> </chat-topbar> <nav-ui> <nav-item-ui text="Today's chat" selected></nav-item-ui> <nav-item-ui text="API design review"></nav-item-ui> <nav-item-ui text="Architecture proposal"></nav-item-ui> </nav-ui> </chat-sidebar> <chat-header>...</chat-header> <chat-thread>...</chat-thread> <chat-composer>...</chat-composer> </chat-shell>

## Authoring rules

- Cluster-namespaced children only. Use `<chat-header>`, `<chat-thread>`, `<chat-composer>`, `<chat-sidebar>`. Don't author raw `<header data-chat-name>` or `<section data-chat-messages>` — these no longer style or wire.
- State is queryable as attributes. `shell.querySelector('chat-thread').hasAttribute('streaming')`. Style cross-cuts via `:has()`; no JS coordination needed.
- Empty state wraps in `<chat-empty>` inside `<chat-thread>`. The thread hides the empty wrapper automatically when the first message arrives.
- Composer wraps `<chat-input-ui>`. Don't put `<chat-input-ui>` as a direct child of `<chat-shell>`.

## Where to next

- chat-shell component reference — full anatomy + live demo
- chat-thread · chat-composer · chat-input-ui
- Macro-shells overview
- admin-shell pattern (counterpart for admin/dashboard surfaces)