# DonnyAvatar

> The assistant's animated avatar with thinking, speaking, and idle mood states, used inside ChatWidget and Donny surfaces.

- Status: stable
- Group: display
- Page: https://www.digitaltableteur.com/design-system/components/donny-avatar
- Contract: https://www.digitaltableteur.com/contracts/v1/DonnyAvatar.contract.json

## When to use

The assistant's animated avatar with mood and lifecycle states used inside ChatWidget and Donny surfaces. DONNY_STATES and isDonnyState expose the complete validated state vocabulary to hosts.

## When not to use

- Do not set decorative on a DonnyAvatar unless the parent control carries its own accessible name; a decorative avatar is hidden from assistive technology and names nothing.
- Do not drive lifecycle-only states such as loading or typing from decorative marketing copy.
- Do not use random emotional states to imply work or success that has not occurred.

## Look-alikes

The contract names no look-alike with a deciding condition.

## Props

| Prop | Type | Default | Description | Required |
| --- | --- | --- | --- | --- |
| `state` | `"success" \| "error" \| "loading" \| "idle" \| "listening" \| "thinking" \| "searching" \| "confused" \| "handoff" \| "greeting" \| "acknowledging" \| "suggesting" \| "confident" \| "curious" \| "celebrating" \| "apologetic" \| "typing" \| "waving" \| "remembering" \| "focused" \| "playful" \| "impressed" \| "skeptical" \| "sleepy" \| "sleeping"` | `idle` | Current expression or assistant lifecycle state. | No |
| `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `md` | Rendered avatar size: xs 28px (chat toggle), sm 32px, md 48px, lg 64px, xl 96px. | No |
| `className` | `string` | none | Additional CSS class. | No |
| `onTransitionEnd` | `() => void` | none | Called when the state transition animation ends. | No |
| `showLabel` | `boolean` | `false` | Shows the current state label for diagnostics. | No |
| `trackMouse` | `boolean` | `false` | Makes the eyes follow the pointer. | No |
| `proximitySelectors` | `string[]` | `[]` | CSS selectors whose pointer proximity can trigger curious or playful behavior. | No |
| `onProximityChange` | `(isNearTarget: boolean, targetSelector?: string) => void` | none | Called when proximity to a tracked target changes. | No |
| `proximityThreshold` | `number` | `150` | Pointer proximity threshold in pixels (default 150). | No |
| `enableIdleExpressions` | `boolean` | `false` | Enables one randomized idle expression before the avatar settles. | No |
| `idleExpressionInterval` | `number` | `12000` | Delay before the one idle expression, in milliseconds (default 12000), randomized by 50 percent. | No |
| `isSpeaking` | `boolean` | `false` | Animates the mouth during streaming responses. | No |
| `enableSleepDetection` | `boolean` | `false` | Enables sleepy and sleeping states after pointer inactivity. | No |
| `sleepyDelay` | `number` | `120000` | Inactivity delay before the sleepy state, in milliseconds (default 120000). | No |
| `sleepDelay` | `number` | `150000` | Inactivity delay before the sleeping state, in milliseconds (default 150000). | No |
| `decorative` | `boolean` | `false` | Sets aria-hidden and removes role and label when a parent control owns the accessible name (e.g. the chat toggle). Otherwise the avatar is an img named by its translated state, such as "Donny is thinking". | No |

## Variants

- Available sizes: `xs`, `sm`, `md`, `lg`, `xl` (default `md`).
- Allowed `state` values: `success`, `error`, `loading`, `idle`, `listening`, `thinking`, `searching`, `confused`, `handoff`, `greeting`, `acknowledging`, `suggesting`, `confident`, `curious`, `celebrating`, `apologetic`, `typing`, `waving`, `remembering`, `focused`, `playful`, `impressed`, `skeptical`, `sleepy`, `sleeping` (default `idle`).

## Invalid combinations

The contract records no invalid combinations.

## Keyboard

The contract records no keyboard interaction.

## Rules

Every item under When not to use is a MUST NOT. MUST and SHOULD follow RFC 2119.

| Level | Rule | How it is checked |
| --- | --- | --- |
| MUST | ARIA: When not decorative, the root is role=img named by a translated sentence for its state (`donnyAvatar.state.<state>`, for example "Donny is thinking", "Donny miettii", "Donny tänker"); raw state ids are never announced. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | ARIA: Decorative sets aria-hidden on the root and removes the role and the name, so the parent control must carry the accessible name. | Not yet verified: no evidence record. WCAG 4.1.2. |
| MUST | Required stories produce no axe violations at the configured severity. | Automated by `npm run test:stories:matrix:ci`. WCAG 2.5.8. |
| MUST | The accessibility tree (role, name, state) matches the committed snapshot for every required story. | Automated by `npm run test:stories:matrix:ci`. WCAG 1.3.1, 4.1.2. |
| MUST | The component remains legible and operable under a real browser forced-colors: active pass. | Automated by `npm run test:stories:hc`. |
| MUST | A human completed an end-to-end accessibility review of this component. | Manual review, last on 2026-11-04. |
| SHOULD | Use lifecycle states such as listening, thinking, searching, typing, and loading to reflect actual assistant work. | Not stated in the contract. |
| SHOULD | Set decorative when Donny sits inside an already-labelled button or link. | Not stated in the contract. |
| SHOULD | Validate external state strings with isDonnyState before rendering. | Not stated in the contract. |

## Install and import

- In-repo only. DonnyAvatar is not exported from `@digitaltableteur/react`, so there is no public import path.

## Links

- Machine-readable contract (Design System Contract 1.0): https://www.digitaltableteur.com/contracts/v1/DonnyAvatar.contract.json
- Markdown version of this page: https://www.digitaltableteur.com/design-system/components/donny-avatar.md
- Component index as JSON: https://www.digitaltableteur.com/design-system/components.json
- All components: https://www.digitaltableteur.com/design-system/components
- Source: The implementation lives in a private repository. This page, its Markdown twin and the contract are generated from it at build time and are the public source of truth.
