Build a chat
The AI components are designed to stack into one anatomy: what the user said, what the assistant did, and what it answered. This guide composes a complete conversation screen from eight of them.
0. Install the parts
One command brings in everything this guide uses, dependencies included.
npx shadcn-svelte@latest add https://mizu-ui.com/r/v0.1.4/chat-bubble.json https://mizu-ui.com/r/v0.1.4/chat-input.json https://mizu-ui.com/r/v0.1.4/reasoning.json https://mizu-ui.com/r/v0.1.4/tool-call.json https://mizu-ui.com/r/v0.1.4/streaming-text.json https://mizu-ui.com/r/v0.1.4/sources.json https://mizu-ui.com/r/v0.1.4/message-actions.json https://mizu-ui.com/r/v0.1.4/prompt-suggestions.json 1. Messages
Conversations are two voices: the user on the accent, the assistant on the quiet fill. Bubbles animate in on arrival by default.
<script lang="ts">
import { ChatBubble } from '$lib/components/ui/chat-bubble';
</script>
<div class="flex flex-col gap-2.5">
<ChatBubble role="user">Find somewhere quiet for dinner Saturday.</ChatBubble>
<ChatBubble role="assistant">On it. Checking your usual spots first.</ChatBubble>
</div>2. Show the work
Between the question and the answer lives the work. Reasoning folds the chain of thought into a quiet disclosure; Tool Call reports each thing the assistant actually did.
<script lang="ts">
import { Reasoning } from '$lib/components/ui/reasoning';
import { ToolCall } from '$lib/components/ui/tool-call';
</script>
<Reasoning summary="Thought for 4 seconds">
Quiet matters more than fancy. Check the corner table at Verde first.
</Reasoning>
<ToolCall name="Checked Verde's availability" detail="Saturday, 7:00 PM" state="done">
Two openings Saturday evening. The 7:00 slot holds the corner table.
</ToolCall>3. The answer, streaming
Streaming Text types the reply in token by token. Ground it with Sources and finish with Message Actions so every answer can be copied, rated, or regenerated.
<script lang="ts">
import { ChatBubble } from '$lib/components/ui/chat-bubble';
import { StreamingText } from '$lib/components/ui/streaming-text';
import { Sources } from '$lib/components/ui/sources';
import { MessageActions } from '$lib/components/ui/message-actions';
const reply = 'Booked for Saturday at seven. I picked the corner table you liked.';
</script>
<ChatBubble role="assistant" class="w-full max-w-[85%]">
<StreamingText text={reply} speed={70} />
</ChatBubble>
<Sources items={[{ label: 'verde.rest', url: 'https://verde.rest' }]} />
<MessageActions text={reply} />4. The composer
Prompt Suggestions invite the next message; Chat Input carries attach, voice, and send in one
pill. Wire onSubmit to your model call and you have a working chat.
<script lang="ts">
import { ChatInput } from '$lib/components/ui/chat-input';
import { PromptSuggestions } from '$lib/components/ui/prompt-suggestions';
let value = $state('');
</script>
<PromptSuggestions
items={['Make it 8pm instead', 'Add it to my calendar']}
onSelect={(p) => (value = p)}
/>
<ChatInput bind:value placeholder="Message Era..." onSubmit={(m) => send(m)} />5. All together
Stacked in order inside a card, the pieces read as one screen: messages, the work, the streaming answer, the composer. The finished version ships as the Assistant chat block; grab the whole thing with one command or copy its source from the Blocks page.
npx shadcn-svelte@latest add https://mizu-ui.com/r/v0.1.4/assistant-chat.json