Skip to content
Tier

Strength meter

Pro

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.

Markdown
Version 5.2.0· other versions

This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).

Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1, 2.6.2, 2.7.0, 2.8.0, 2.9.0, 2.10.0, 3.0.0, 4.0.0, 4.0.1, 4.0.2, 4.1.0, 4.2.0 and 4.3.0: the page came later, or had another name then.

Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.

Preview

Loading the preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/strength-meter

Brings in: locale, motion, tokens, utils

Usage

TSX · The example above
"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>

PropTypeDefaultDescription
scorerequiredStrengthScore | null—The app's score, 0 (very weak) to 4 (very strong), or `null` while nothing has been checked.
basisrequiredstring—What the score is measured by, shown under the meter: "zxcvbn's estimate", "the server's policy check". Required.
labelstring | undefined—The meter's name: "Password strength" by default.
classNamestring | undefined—Classes for the outer box.

Strings

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

KeyEnglish
labelPassword strength
score0Very weak
score1Weak
score2Fair
score3Strong
score4Very strong
notCheckedNot checked
basisMeasured by {basis}

Motion

MomentFamilyWhat it does
scorefillThe 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.

Types

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