# Confirm field

A second entry that has to equal the first: a new password, an email typed twice, a name typed to confirm. It says "Matches" or "Doesn't match yet" under the field once the person stops typing (600 ms after the last key) or leaves the field, never per key, so nothing nags while they type. The words are in a polite live region that is there from the start, so each judgement is read once. Nothing is said while the field is empty.

Whether a mismatch stops a submit is the app's: `onMatchChange` tells it each time the judgement changes.

- Registry name: `confirm-field` (`@candor/confirm-field`)
- 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/confirm-field

## Install

```bash
npx candor-ui add confirm-field
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/confirm-field`.
It brings in: input, label, locale, motion, tokens, utils.

## Example

```tsx
"use client"

import * as React from "react"
import { Field } from "@/components/candor/ui/field"
import { Input } from "@/components/candor/ui/input"
import { ConfirmField } from "@/components/candor/ui/confirm-field"

// The second entry is judged once the person pauses or leaves the field, never per key. Whether a mismatch stops the
// submit is the app's.
export default function Example() {
  const [password, setPassword] = React.useState("")
  const [matches, setMatches] = React.useState<boolean | null>(null)
  return (
    <div className="flex w-full max-w-sm flex-col gap-4">
      <Field label="New password">
        <Input type="password" autoComplete="new-password" value={password} onChange={(e) => setPassword(e.target.value)} />
      </Field>
      <ConfirmField label="Confirm new password" type="password" autoComplete="new-password" value={password} onMatchChange={setMatches} />
      <p className="text-xs text-muted-foreground">The app can save: {matches === null ? "not judged yet" : matches ? "yes" : "no"}</p>
    </div>
  )
}
```

## <ConfirmField>

Props:

- `value: string`: The first entry, which this one has to equal.
- `label: string`: The field's name: "Confirm password".
- `onMatchChange?: ((matches: boolean) => void) | undefined`: Called with whether the entries match, each time the judgement changes (after a pause or on leaving the field).

Also takes the props of `Omit<React.ComponentProps<typeof Input>, "value">`.

## Strings (`confirmField`)

The fixed words, English by default. Override any of them under `confirmField` in `<LocaleProvider strings={{ confirmField: { … } }}>`; the table is exported as `confirmFieldStrings`.

- `matches`: Matches
- `noMatch`: Doesn't match yet

## Motion

- **match** (mark, draw): A tick draws beside "Matches" when the entries first match after the person pauses or leaves the field; never per key.

Set with `--cd-motion-confirm-field-<moment>-*` in your brand file; the families are in the design reference.

## 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`.
