# useAnnouncer

Announces a message to screen-reader users from app code: `const announce = useAnnouncer(); announce("Saved")`, or `announce("Connection lost", "assertive")` for something that can't wait. The same words announced twice are spoken twice, which a live region of your own that is given the same text again doesn't do. An announcement is cleared from the page a few seconds after it is made, so a screen reader reading the page later doesn't find stale words.

Every component that uses the hook shares one visually hidden live region per politeness, put in `document.body` when the first of them mounts, so the region is there before the first message (a region added with its text is often not read), and taken away when the last unmounts. The text is plain text, never HTML, with bidi controls marked by `neutralizeBidi`, so text from a model or a tool can be announced as it is. An announcement made while no component using the hook is mounted, or on the server, does nothing.

- Registry name: `use-announcer` (`@candor/use-announcer`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/use-announcer

## Install

```bash
npx candor-ui add use-announcer
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/use-announcer`.
It brings in: bidi, tokens.

## Example

```tsx
"use client"

import * as React from "react"
import { Button } from "@/components/candor/ui/button"
import { useAnnouncer } from "@/lib/candor/use-announcer"

export default function Example() {
  const announce = useAnnouncer()
  const [saves, setSaves] = React.useState(0)
  return (
    <div className="flex flex-col items-start gap-2">
      <Button
        variant="outline"
        size="sm"
        onClick={() => {
          setSaves((n) => n + 1)
          // Said again on every press, though the words are the same.
          announce("Draft saved")
        }}
      >
        Save draft
      </Button>
      <p className="text-xs text-muted-foreground">Saved {saves} times. A screen reader hears “Draft saved” each time.</p>
    </div>
  )
}
```

## Functions

### useAnnouncer

```ts
useAnnouncer()
```

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
