# Strength meter

How strong a password (or a passphrase, a key) is, on a 0 to 4 scale in four segments, with the word for the score ("Fair"). The score is the app's, from an estimator such as zxcvbn; the meter never guesses. `basis` is required and shown under the meter, so a person can tell what measured it ("Measured by zxcvbn's estimate"): a meter that doesn't say what it measures can't be trusted. With `score` `null` it says "Not checked" and fills nothing.

Screen readers hear a meter named by `label` with the word as its value. The segments are drawn as bordered boxes, so forced colours keep how far it is filled.

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

## Install

```bash
npx candor-ui add strength-meter
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/strength-meter`.
It brings in: 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 { StrengthMeter, type StrengthScore } from "@/components/candor/ui/strength-meter"

// The score is the app's, from its estimator; here a stand-in by length and kinds of character, and the basis says so.
// A real app passes zxcvbn's score and says "zxcvbn's estimate".
const estimate = (text: string): StrengthScore | null => {
  if (!text) return null
  const kinds = [/[a-z]/, /[A-Z]/, /\d/, /[^\w]/].filter((r) => r.test(text)).length
  return Math.max(0, Math.min(4, Math.floor(text.length / 4) + kinds - 2)) as StrengthScore
}

export default function Example() {
  const [password, setPassword] = React.useState("")
  return (
    <div className="flex w-full max-w-sm flex-col gap-3">
      <Field label="New password">
        <Input type="password" autoComplete="new-password" value={password} onChange={(e) => setPassword(e.target.value)} />
      </Field>
      <StrengthMeter score={estimate(password)} basis="this example's length and character check" />
    </div>
  )
}
```

## <StrengthMeter>

Props:

- `score: StrengthScore | null`: The app's score, 0 (very weak) to 4 (very strong), or `null` while nothing has been checked.
- `basis: string`: What the score is measured by, shown under the meter: "zxcvbn's estimate", "the server's policy check". Required.
- `label?: string | undefined`: The meter's name: "Password strength" by default.
- `className?: string | undefined`: Classes for the outer box.

## Strings (`strengthMeter`)

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

- `label`: Password strength
- `score0`: Very weak
- `score1`: Weak
- `score2`: Fair
- `score3`: Strong
- `score4`: Very strong
- `notChecked`: Not checked
- `basis`: Measured by {basis}

## Types

### StrengthScore

A score on the 0 to 4 scale password estimators use (zxcvbn's), or `null` for not checked.

```ts
0 | 1 | 2 | 3 | 4
```

## Motion

- **score** (fill): The segments fill to the app's new score; one drawn with a score is still.

Set with `--cd-motion-strength-meter-<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`.
