# Context meter
> Context-window meter that fills a pixel strip behind a glowing front, turns amber at 80% and red at 95%, and animates compaction.
- React: `import { UiContextMeter } from "@/components/lumesec/ui-context-meter"`
- Collection: Interaction (https://elements.lumesec.ai/components/interaction)
- Registry item: https://elements.lumesec.ai/r/ui-context-meter.json
- Page: https://elements.lumesec.ai/components/interaction/context-meter



Live preview: https://elements.lumesec.ai/view/ui-context-meter

Demo source:

```tsx
"use client";

import * as React from "react";

import { UiContextMeter, type UiContextMeterHandle } from "@/components/lumesec/ui-context-meter";

const ACTION =
  "h-[30px] rounded-lg border border-border bg-card px-[11px] text-[12.5px] font-medium text-foreground hover:border-[color-mix(in_srgb,var(--lumesec)_50%,var(--border))]";

export default function UiContextMeterDemo() {
  const meter = React.useRef<UiContextMeterHandle>(null);
  return (
    <div className="grid w-full max-w-[400px] gap-4">
      <div className="rounded-[14px] border border-border bg-card px-5 py-[18px] shadow-[0_14px_34px_-20px_rgb(0_0_0/0.4)]">
        <UiContextMeter ref={meter} defaultValue={46} capacity={200000} />
      </div>
      <div className="flex flex-wrap justify-center gap-1.5">
        <button type="button" className={ACTION} onClick={() => meter.current?.add(14)}>
          Add a file (+14 %)
        </button>
        <button type="button" className={ACTION} onClick={() => meter.current?.compact()}>
          Compact
        </button>
      </div>
    </div>
  );
}
```

## Playground

Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over.

## Installation

```bash
npx shadcn@latest add @lumesec/ui-context-meter
```

First time with the @lumesec registry? Register it once, or install by URL:

```bash
npx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.json
npx shadcn@latest add https://elements.lumesec.ai/r/ui-context-meter.json
```

## Usage

React:

```tsx
"use client";

import * as React from "react";

import { UiContextMeter, type UiContextMeterHandle } from "@/components/lumesec/ui-context-meter";

export function Example() {
  const meter = React.useRef<UiContextMeterHandle>(null);
  return (
    <div className="grid gap-3">
      <UiContextMeter ref={meter} defaultValue={46} capacity={200000} />
      <button type="button" onClick={() => meter.current?.compact()}>
        Compact
      </button>
    </div>
  );
}
```

## Behaviour

Usage fills a strip of pixels behind a glowing front, turns amber past 80 % and red near the limit. Compacting sends a bright band back across the strip as the count drops.

## API reference

### Props

Also accepts every prop of `<div>` (`React.ComponentProps<"div">`), spread onto the root element.

| Prop            | Type                                 | Default     | Description                                                                                                                          |
| --------------- | ------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `value`         | `number`                             | —           | Controlled share of the context window in percent, clamped to 0–100. The strip animates to each new level. Use with `onValueChange`. |
| `defaultValue`  | `number`                             | `0`         | Initial percentage when uncontrolled.                                                                                                |
| `capacity`      | `number`                             | `200000`    | Window size in tokens, used only for the "used / total" readout, which is shown in thousands.                                        |
| `label`         | `string`                             | `"Context"` | Caption before the percentage.                                                                                                       |
| `onValueChange` | `(value: number) => void`            | —           | Called with the new percentage when `add()` or `compact()` changes it.                                                               |
| `onCompact`     | `(from: number, to: number) => void` | —           | Called when `compact()` runs, with the percentage before and after.                                                                  |
| `ref`           | `React.Ref<UiContextMeterHandle>`    | —           | Exposes `add()` and `compact()`.                                                                                                     |

### Ref

`ref` receives a `UiContextMeterHandle` handle with these methods.

| Method                       | Description                                                                                                                                  |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `add(percent: number): void` | Adds `percent` percentage points (negative to subtract), clamped to 0–100.                                                                   |
| `compact(): void`            | Drops usage to 28% of its current value (at least 12%), runs a bright sweep and shows "Compacting…" for 1.5 s. Does nothing at 15% or below. |

## Accessibility

* The strip is a canvas with `role="meter"`, `aria-valuemin="0"`, `aria-valuemax="100"`, `aria-valuenow` and the `aria-label` "Context window N% full".
* The `aria-label` is fixed English and does not use `label`.
* There is no live region; changes are not announced.
* Reduced motion: the fill jumps to the new level, the compaction sweep is skipped, the percentage stops blinking near the limit and text swaps without rolling.

## Theming

Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from `--lumesec`. See [Theming](/docs/theming).

This component reads `--lumesec`, `--lumesec-glint`, `--lumesec-warning`, `--destructive`, `--foreground` and `--muted-foreground`.

## Notes

* `value` is a percentage, not a token count; the token readout is derived from `capacity`.
* The root carries `data-zone` set to `ok`, `warn` (80% and up) or `full` (95% and up), which can be used for styling.
* The strip is 18 px tall and fills the available width. Its colours follow the theme and are re-read when it changes.


