# Lock Status Badge

Lock Status Badge [#lock-status-badge]

The **Lock Status Badge** is a compact chip that shows the session-lock state of
an encrypted vault: `locked`, `unlocked`, or `no-vault`. Each state has distinct
iconography and an accessible text label (state is announced as text, never color
alone).

> **Presentational and key-safe.** The badge holds no key material and performs no
> crypto — pass the current lock state in. Recommended LocalMode source: the
> `status` field of `useEncryptedVault` from `@localmode/react` (map its
> `'uninitialized' | 'locked' | 'unlocked'` onto `'no-vault' | 'locked' |
> 'unlocked'`) — a recommendation, never a requirement.

**When to use it:** any header, toolbar, or item list that needs to surface
whether an encrypted vault is currently locked.

Preview [#preview]

```tsx
'use client';

import { useState } from 'react';

import { LockStatusBadge, type LockStatus } from '@/components/lock-status-badge';

const STATUSES: LockStatus[] = ['no-vault', 'locked', 'unlocked'];

/**
 * Demo for LockStatusBadge, used by the docs live preview. Fixture-driven —
 * cycles through the three lock states on click. No crypto, no model.
 */
export default function LockStatusBadgeDemo() {
  const [index, setIndex] = useState(1);
  const status = STATUSES[index];

  return (
    <div className="flex flex-col items-start gap-3">
      <div className="flex flex-wrap items-center gap-2">
        {STATUSES.map((s) => (
          <LockStatusBadge key={s} status={s} />
        ))}
      </div>
      <button
        type="button"
        onClick={() => setIndex((i) => (i + 1) % STATUSES.length)}
        className="inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-xs font-medium transition-colors hover:bg-accent"
      >
        Cycle state
      </button>
      <p className="text-xs text-muted-foreground">
        Current: <LockStatusBadge status={status} />
      </p>
    </div>
  );
}
```

Installation [#installation]

```bash
npx shadcn@latest add @localmode/ui/security-privacy/lock-status-badge
```

Dependencies [#dependencies]

* **Data source:** renders the `status` you pass. Works with any backend. Recommended LocalMode hook: `useEncryptedVault` (optional).
* `lucide-react` — icons
* `clsx` + `tailwind-merge` — via the shared `cn()` util (installed automatically as a registry dependency)

Files installed [#files-installed]

* `lock-status-badge.tsx` — the component
* `lib/utils.ts` — the `cn()` helper (if not already present)

Props [#props]

**LockStatusBadge**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `status` | `LockStatus` | — | **Required.** The vault's session lock state. `no-vault` is the pre-initialization state (nothing to unlock yet); `locked` means an initialized vault whose key is not in memory; `unlocked` means the derived key is held in memory. |
| `label` | `string` | — | Override the default per-state text. The default labels are "Locked" / "Unlocked" / "No vault". |

Examples [#examples]

Reflect the vault's lock state [#reflect-the-vaults-lock-state]

```tsx
import { useEncryptedVault } from '@localmode/react';
import { LockStatusBadge } from '@/components/lock-status-badge';

export function VaultHeader() {
  const { status } = useEncryptedVault({ name: 'notes' });
  return <LockStatusBadge status={status === 'uninitialized' ? 'no-vault' : status} />;
}
```

Custom label [#custom-label]

```tsx
<LockStatusBadge status="unlocked" label="Session open" />
```

Customization [#customization]

Each state's icon and semantic token classes live in a small `STATUS_CONFIG` map
in the copied file — swap the icons, retune the colors, or change the default
labels to match your design system. Because you own the file, the state-to-token
mapping is yours to change.