---
title: Message Typing
description: Animated three-dot typing indicator for chat threads
visibility: guest
draft: false
---

# Message Typing

The three bouncing dots that say *someone is composing*. Drop it at the end of a
thread while the other side types — or while an assistant works — and it reads
as the next [Message](/components/message) about to arrive.

## Basic Usage

:::preview{title="A typing indicator in a thread"}
<div style="width: 24rem; max-width: 100%; margin-inline: auto;">
    <x-wirekit::stack gap="md">
        <x-wirekit::message :author="['name' => 'Ada']" timestamp="2026-07-17 09:14">Give me one second…</x-wirekit::message>
        <x-wirekit::message-typing author="Ada" />
    </x-wirekit::stack>
</div>
:::

:::source{language="blade"}
<x-wirekit::stack gap="md">
    <x-wirekit::message :author="['name' => 'Ada']" timestamp="2026-07-17 09:14">Give me one second…</x-wirekit::message>
    <x-wirekit::message-typing author="Ada" />
</x-wirekit::stack>
:::

## Sides

`side` mirrors [Message](/components/message)'s alignment, so the indicator sits
on whichever side the person typing is on.

:::preview{title="Both sides"}
<div style="width: 24rem; max-width: 100%; margin-inline: auto;">
    <x-wirekit::stack gap="md">
        <x-wirekit::message-typing author="Ada" side="left" />
        <x-wirekit::message-typing author="You" side="right" />
    </x-wirekit::stack>
</div>
:::

:::source{language="blade"}
<x-wirekit::stack gap="md">
    <x-wirekit::message-typing author="Ada" side="left" />
    <x-wirekit::message-typing author="You" side="right" />
</x-wirekit::stack>
:::

## Announcing

By default the indicator is **silent** to assistive technology. That is
deliberate: a thread that announces every keystroke-driven typing flicker is
unusable with a screen reader. Turn `announce` on for a single, stable "the
assistant is working" row.

```blade
{{-- 1. One stable row while the assistant works — safe to announce --}}
<x-wirekit::message-typing author="Assistant" announce />

{{-- 2. A per-keystroke human typing flicker — leave it silent (default) --}}
@if($someoneIsTyping)
    <x-wirekit::message-typing :author="$typistName" />
@endif
```

## Livewire

Bind it to whatever your presence channel already tracks:

```blade
{{-- 1. $typing comes from your Echo presence / whisper handler --}}
@if($typing)
    <x-wirekit::message-typing :author="$typing" />
@endif
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `author` | string\|null | `null` | Who is typing — shown as an avatar + name above the dots, and in the announcement. Null keeps the bare, anonymous bubble |
| `side` | string | `'left'` | `left` or `right`, mirroring Message |
| `announce` | bool | `false` | Render as a polite live region |
| `scope` | string\|null | `null` | Scoped personalization name |

## Accessibility

- The dots are **decorative** (`aria-hidden`); the meaning lives in a
  visually-hidden "Ada is typing…" text.
- Under `prefers-reduced-motion: reduce` the dots freeze. Because the meaning is
  in the text and not the motion, a reduced-motion user loses nothing.
- `announce` is **opt-in** — a live region per typing flicker would flood a
  screen reader.

## Keyboard Interaction

This component is presentational and does not respond to keyboard input.

## Pitfalls

- **Do not announce a per-keystroke indicator.** Reserve `announce` for one
  stable working row.
- **Remove it when the message lands.** A typing indicator that outlives the
  reply reads as a stuck UI.

## Design Tokens

| Element | Token |
| --- | --- |
| Bubble surface | `--color-wk-bg-elevated` |
| Bubble border | `--color-wk-border-subtle`, `--border-wk-width` |
| Bubble radius | `--radius-wk-lg` |
| Dot color | `--color-wk-text-subtle` |
| Dot radius | `--radius-wk-full` |

## Further Reading

- [MDN: `prefers-reduced-motion`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion)
- [WAI-ARIA: `status` role](https://www.w3.org/TR/wai-aria-1.2/#status)
