---
title: Strength Meter
description: A row of bars for how hard a value is to guess, with the step named for screen readers and spoken when it changes.
visibility: guest
draft: false
---

# Strength Meter

The `<x-wirekit::strength-meter>` component shows how hard something is to guess as a row of bars that light up and change color, the same display the [Password Input](/components/password-input) uses for its `strength-meter`. It has no field of its own: you hand it a step, from a code generator, a passphrase built from settings, or a strength your server computes.

## Usage

Pass `value` from 0 to 4 and a `label` that names what is judged:

:::preview{title="Four steps"}
<x-wirekit::stack style="width: 24rem; max-width: 100%" gap="md">
    <x-wirekit::strength-meter :value="1" label="Code strength" show-level />
    <x-wirekit::strength-meter :value="2" label="Code strength" show-level />
    <x-wirekit::strength-meter :value="3" label="Code strength" show-level />
    <x-wirekit::strength-meter :value="4" label="Code strength" show-level />
</x-wirekit::stack>
:::

One bar is red, two and three are amber, and all four are green. The number of lit bars says the same as the color, so the meter does not depend on color alone. `show-level` writes the step's word beside the bars. A value of 0 lights nothing and names no step.

## Other Step Counts

`max` sets the number of bars. Four bars have a word for each step (Weak, Fair, Good, Strong); any other count says where it stands, "3 of 5", unless you name the steps with `levels`, weakest first and one per bar:

:::preview{title="Five named steps"}
<x-wirekit::strength-meter
    style="width: 24rem; max-width: 100%"
    :value="4"
    :max="5"
    label="Passphrase strength"
    :levels="['Very weak', 'Weak', 'Fair', 'Strong', 'Very strong']"
    show-level
/>
:::

The color follows the share of lit bars: the first quarter of the steps is red, the steps below the top are amber, and the top step is green.

## From a Strength You Compute

The component takes a step, not a formula, because how many bits are enough depends on what is being guessed and how often a guess can be tried. A code that is checked by a rate-limited form needs far fewer than a password an attacker can test offline. Map your estimate to steps where you know that, for example from the bits of a random code:

```php
// 1. The bits of a random code: length times log2 of the alphabet size
$bits = $length * log(strlen($alphabet), 2);

// 2. Your own thresholds, for how the code is used
$step = match (true) {
    $bits >= 60 => 4,
    $bits >= 40 => 3,
    $bits >= 28 => 2,
    default => 1,
};
```

```blade
{{-- 3. Livewire re-renders the meter as the settings change --}}
<x-wirekit::strength-meter :value="$step" label="Code strength" show-level />
```

A value computed in the browser binds with `x-model` instead, from an Alpine scope around the meter:

```blade
<div x-data="{ length: 12, strength: 2 }">
    <input type="range" min="4" max="24" x-model.number="length" x-on:input="strength = length / 6">
    {{-- The meter follows the bound property; a fraction rounds to a whole step --}}
    <x-wirekit::strength-meter x-model="strength" label="Code strength" />
</div>
```

Either way, a changed step is spoken through a polite status region as "Code strength: Strong". The step the page loads with is not spoken.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `value` | `int` | `0` | The lit steps, from 0 to `max`. A fraction rounds to a whole step, and a value out of range is clamped |
| `max` | `int` | `4` | How many bars, and so how many steps |
| `label` | `string\|null` | `'Strength'` | The meter's accessible name, and the subject of what it says when the step changes |
| `levels` | `array\|null` | `null` | What each step is called, weakest first, one per bar. Four bars default to Weak, Fair, Good and Strong; any other count to "2 of 5" |
| `showLevel` | `bool` | `false` | Also show the current step's word beside the bars |
| `announce` | `bool` | `true` | Speak a changed step through a polite status region. Turn it off where the page already says it |
| `scope` | `string\|null` | `null` | Scoped personalization key |

## Accessibility

- The bars sit in an element with `role="meter"`, named by `label`, with `aria-valuemin`, `aria-valuemax`, `aria-valuenow` and the step's word as `aria-valuetext`. A reader hears "Code strength, Strong" rather than "3 of 4".
- The values are rendered by the server as well, so the meter is complete before Alpine starts.
- A changed step is spoken once, politely, with the meter's name in the sentence: a step's word alone would not say what it judges. The region is in the page from the start and empty until the first change.
- The step is carried by the number of lit bars as well as by their color (WCAG 1.4.1). `show-level` adds the word on screen for readers who want it spelled out.

## Keyboard Interaction

The meter is presentational and takes no focus: it describes a value that something else on the page sets. A screen reader reaches it in reading order, and hears a changed step through the status region wherever focus is.

## Design Tokens

| Element | Token |
| --- | --- |
| Unlit bar | `--color-wk-bg-muted` |
| First quarter of the steps | `--color-wk-danger` |
| Steps below the top | `--color-wk-warning` |
| Top step | `--color-wk-success` |
| Step word | `--color-wk-text-muted` |
| Gap between the bars and the word | `--gap-wk-sm` |
| Bar color transition | `--transition-wk-duration` |

## Further Reading

- [Password Input](/components/password-input), which draws the same bars for its own field
- [MDN: `meter` role](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Roles/meter_role)
