# 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. A standing "Matches" is withdrawn at once when either entry changes, so it is never shown for entries that no longer match.

Whether a mismatch stops a submit is the app's: `onMatchChange` tells it each time the judgement changes, and `false` at once when a match is withdrawn, including by the field going while it stood.

The second entry is the field's own, starting at `defaultValue`, unless you control it with `entry` and `onEntryChange`: then setting `entry=""` resets it, and its judgement goes with it (a `key` resets an uncontrolled one). An entry you set yourself is judged at once. The two entries are compared as Unicode text, after `normalize("NFC")`, so a name typed with a combining accent matches the same name typed with an accented letter; case and spacing still count, since the first entry is the one to type.

- 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), and with `false` at once when a standing match is withdrawn because either entry changed, or because the field went (a `key` reset it, or it unmounted).
- `entry?: string | undefined`: The second entry, what the person has typed, when you control it. Set it to `""` to reset the field: nothing is then said. Left out, the field keeps its own, starting at `defaultValue`.
- `onEntryChange?: ((entry: string) => void) | undefined`: Called with the second entry as the person types.

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