Skip to content
Brok UI

Loading…

No results

Meters

Open source

Single-value readouts of a fraction of a whole — an arc gauge, a circular progress ring, linear/radial usage readouts and a liquid-fill gauge.

Version
v1.2.1
Stability
stable
License
MIT
Related
Circular Progress
Usage Meter
Usage Gauge
Liquid Chart
1 of 5

Gauge — A static radial arc meter rendering a value as a 270° gauge or 180° semicircle with a track, coloured progress arc and centred numeric readout. Shares its `tone` vocabulary with circular-progress.

Preview

72
CPU load
45
Disk usage
93
Uptime
previews.components.gauge.default.blade.php Blade
<div class="w-full flex flex-wrap items-end justify-center gap-8">
    <div class="flex flex-col items-center gap-2">
        <x-ui.gauge :value="72" />
        <span class="text-sm text-muted-foreground">CPU load</span>
    </div>
    <div class="flex flex-col items-center gap-2">
        <x-ui.gauge :value="45" tone="attention" variant="semi" />
        <span class="text-sm text-muted-foreground">Disk usage</span>
    </div>
    <div class="flex flex-col items-center gap-2">
        <x-ui.gauge :value="93" :max="100" tone="positive" />
        <span class="text-sm text-muted-foreground">Uptime</span>
    </div>
</div>

Installation

terminal
php artisan ui:add gauge

Registry contract

php artisan ui:add gauge writes only the files below. The CLI validates each file hash before writing and asks before it replaces a local change, unless you pass --force.

  • blade resources/views/components/ui/gauge.blade.php
Registry dependencies
None — installs on its own.
Packages
composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: install command, usage, props, guidance and the rules. Copy it, or open a prompt about this component in an assistant.

gauge.md
# Brok UI: Gauge (`gauge`)

A static radial arc meter rendering a value as a 270° gauge or 180° semicircle with a track, coloured progress arc and centred numeric readout. Shares its `tone` vocabulary with circular-progress.

Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.

## Install

```bash
php artisan ui:add gauge
```

## Usage

```blade
<div class="w-full flex flex-wrap items-end justify-center gap-8">
    <div class="flex flex-col items-center gap-2">
        <x-ui.gauge :value="72" />
        <span class="text-sm text-muted-foreground">CPU load</span>
    </div>
    <div class="flex flex-col items-center gap-2">
        <x-ui.gauge :value="45" tone="attention" variant="semi" />
        <span class="text-sm text-muted-foreground">Disk usage</span>
    </div>
    <div class="flex flex-col items-center gap-2">
        <x-ui.gauge :value="93" :max="100" tone="positive" />
        <span class="text-sm text-muted-foreground">Uptime</span>
    </div>
</div>
```

## Props

- `value` (int, default `0`) — Current value, clamped between min and max.
- `min` (int, default `0`) — Floor of the value range.
- `max` (int, default `100`) — Ceiling of the value range.
- `size` (int, default `120`) — Outer box size in pixels.
- `thickness` (int, default `10`) — Stroke width in pixels; the canonical name, shared with circular-progress.
- `variant` (string, default `arc`) — arc draws a 270° gauge with the gap at the bottom; semi draws a 180° top half-circle.
- `showValue` (bool, default `true`) — Shows the centred numeric readout.
- `color` (mixed|null, default `null`) — Legacy alias for tone using literal token names (primary, success, warning, destructive).
- `tone` (mixed|null, default `null`) — Opt-in status colour for the arc (positive, attention, negative, neutral); null keeps the brand-primary arc. Same vocabulary as circular-progress's tone.
- `label` (mixed|null, default `null`) — Accessible name for the meter; required by WCAG when the consumer has not set aria-label or aria-labelledby.

## Use when

- Use when trend, distribution, flow, intensity, or relationship questions are easier to answer visually than in raw numbers.
- Reading a value as a dial against a known min/max range, such as a speed, score or utilization gauge.
- Wanting a 270° arc or a 180° semicircle gauge look, rather than a full ring.

## Avoid when

- Do not use a chart when users mainly need exact lookup or when a single metric would be clearer as text or a stat.
- A simple percentage-of-completion ring with no dial reading; use circular-progress instead.
- Several values must compare on shared axes; use chart instead.

## Anti-patterns

- Decorative charts without a meaningful question

## Rules

- Use the `<brok:gauge>` tag (or `<x-ui.gauge>`) in Blade; do not rewrite the component.
- Prefer the documented props and variants over utility-class overrides; when a utility must win, use the `!` important modifier.
- Use semantic design tokens (`bg-primary`, `text-muted-foreground`), never raw colour utilities.
- Keep the `data-slot` attributes; they are the styling and test hooks.

## Links

- Docs: https://brokui.dev/docs/components/gauge
- Registry JSON (files, props, contract): https://brokui.dev/r/open/gauge.json

Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.

API

manifest knowledge + registry-derived coverage

Props

Props accepted by this component: name, type, default value and description.
Prop Type Default Description
value int 0 Current value, clamped between min and max.
min int 0 Floor of the value range.
max int 100 Ceiling of the value range.
size int 120 Outer box size in pixels.
thickness int 10 Stroke width in pixels; the canonical name, shared with circular-progress.
variant string arc arc draws a 270° gauge with the gap at the bottom; semi draws a 180° top half-circle.
showValue bool true Shows the centred numeric readout.
color mixed | null null Legacy alias for tone using literal token names (primary, success, warning, destructive).
tone mixed | null null Opt-in status colour for the arc (positive, attention, negative, neutral); null keeps the brand-primary arc. Same vocabulary as circular-progress's tone.
label mixed | null null Accessible name for the meter; required by WCAG when the consumer has not set aria-label or aria-labelledby.

Slots

  • default — Unused; the gauge renders from props only.

Data slots

Stable hooks for CSS overrides and browser tests.

gauge gauge-indicator gauge-svg gauge-track gauge-value

Behavior

  • Animates the indicator's stroke-dashoffset when value changes, so re-rendering with a new value transitions smoothly.
  • The visible track only spans the arc or semi sweep; the remaining circumference is left as a gap, unlike circular-progress's full ring.
  • An explicit color still works and maps onto the equivalent tone value for backward compatibility.
  • Declares registry capability flags: a11y, responsive, rtl, darkMode, localized, reducedMotion.

Guidance

Chart and visual analytics

Reveal a visual trend, distribution, flow, or relationship.

Use when

  • Use when trend, distribution, flow, intensity, or relationship questions are easier to answer visually than in raw numbers.
  • Reading a value as a dial against a known min/max range, such as a speed, score or utilization gauge.
  • Wanting a 270° arc or a 180° semicircle gauge look, rather than a full ring.

Avoid when

  • Do not use a chart when users mainly need exact lookup or when a single metric would be clearer as text or a stat.
  • A simple percentage-of-completion ring with no dial reading; use circular-progress instead.
  • Several values must compare on shared axes; use chart instead.

Use instead

  • Table for exact lookup
  • Stat for a single value

Anti-patterns

  • Decorative charts without a meaningful question
Anatomy
root gauge-svg gauge-track gauge-indicator gauge-value
Theming hooks
gauge gauge-indicator gauge-svg gauge-track gauge-value

Accessibility

WCAG 2.2 AA Keyboard focus-visible RTL-ready Localized labels Dark mode
Keyboard
No component-owned keyboard interaction; native element behavior applies.
Focus
none
  • role="meter" carries aria-valuenow/min/max plus a friendly aria-valuetext ("value / max (percent%)"), so assistive technology hears a spoken figure, not just the raw number.
  • Always set label, or set your own aria-label/aria-labelledby, so the meter has an accessible name; without either it falls back to a generic "Gauge".
  • Semantic HTML and a stable data-slot attribute for styling and scripting hooks.
  • Focus-visible rings use the ring token, so keyboard focus is always visible.
  • Disabled and invalid states are conveyed to assistive tech, not by color alone.
  • Targets WCAG 2.2 AA; verify contrast in light, dark, admin and customer surfaces in the preview.
  • Labels go through __() and layout uses logical properties (ms-*, text-start), so it mirrors under dir="rtl" — flip the preview to RTL to confirm.
  • Dark mode uses the same semantic tokens under the dark class; high contrast follows forced-color system tokens.

Livewire

Safe

Livewire can update this component through forwarded wire:* attributes.

Source

The exact, editable file ui:add writes into your app. Previews render this same code; there are no preview-only components.

resources/views/components/ui/gauge.blade.php Blade
@props([
    'value' => 0,
    'min' => 0,
    'max' => 100,
    'size' => 120,
    'thickness' => 10,
    'variant' => 'arc',
    'showValue' => true,
    // Deprecated alias for `tone` — a literal token name (primary|success|
    // warning|destructive). Prefer `tone`, the vocabulary circular-progress
    // also speaks (positive|attention|negative|neutral); passing `color`
    // still works and maps onto it below.
    'color' => null,
    // positive | attention | negative | neutral; null keeps the brand-primary
    // arc (same vocabulary and meaning as circular-progress's own `tone` prop).
    'tone' => null,
    // Accessible name — role="meter" requires one (WCAG). Skipped when the
    // consumer supplies aria-label/aria-labelledby themselves.
    'label' => null,
])

@php
    $styles = require base_path(config('ui.component_path', 'resources/views/components/ui').'/_styles.php');
    $variant = $styles['normalizeVariant']($variant);
    $needsName = $label === null && ! $attributes->has('aria-label') && ! $attributes->has('aria-labelledby');

    // Backward-compatible: an explicit `color` (or an omitted one, which
    // defaulted to 'primary') resolves to the equivalent `tone` value.
    $colorToTone = ['success' => 'positive', 'warning' => 'attention', 'destructive' => 'negative', 'primary' => null, 'muted' => 'neutral'];
    $tone = $tone ?? ($color !== null ? ($colorToTone[$color] ?? null) : null);
    // ── Geometry ────────────────────────────────────────────────────────────
    $sizePx = (int) $size;
    $strokeW = (int) $thickness;
    $r = ($sizePx - $strokeW) / 2;          // radius keeps the stroke inside the box
    $cx = $sizePx / 2;
    $cy = $sizePx / 2;
    $circumference = 2 * M_PI * $r;

    // ── Clamped fraction ────────────────────────────────────────────────────
    $span = ($max - $min) != 0 ? ($max - $min) : 1;
    $fraction = ($value - $min) / $span;
    $fraction = max(0.0, min(1.0, $fraction));

    // Sweep portion of the full circle that is actually drawn.
    //   arc  → 270° gap-at-bottom gauge (0.75 of the circle)
    //   semi → 180° top half-circle    (0.50 of the circle)
    $sweep = $variant === 'semi' ? 0.5 : 0.75;

    // The visible track is `sweep` of the circumference; the dash pattern paints
    // `fraction` of that visible arc. The remaining circumference is a gap.
    $visibleLen = $circumference * $sweep;
    $progressLen = $visibleLen * $fraction;

    // arc:  start the sweep at 135° (rotate so the gap sits centred at the bottom).
    // semi: start at 180° so the sweep runs across the top half.
    $rotation = $variant === 'semi' ? 180 : 135;

    // a11y friendly value text.
    $percent = (int) round($fraction * 100);
    $valueText = $value . ($max !== null ? ' / ' . $max : '') . ' (' . $percent . '%)';

    $validTones = ['positive', 'attention', 'negative', 'neutral'];
    $colorClass = in_array($tone, $validTones, true) ? match ($tone) {
        'positive' => 'text-success',
        'attention' => 'text-warning',
        'negative' => 'text-destructive',
        default => 'text-muted-foreground', // neutral
    } : 'text-primary';

    // For `semi` keep the box visually a half-height; arc stays square.
    $boxHeight = $variant === 'semi' ? (int) ceil($sizePx / 2 + $strokeW / 2) : $sizePx;
@endphp

<div
    data-slot="gauge"
    role="meter"
    @if ($label !== null) aria-label="{{ $label }}" @elseif ($needsName) aria-label="{{ __('Gauge') }}" @endif
    aria-valuenow="{{ $value }}"
    aria-valuemin="{{ $min }}"
    aria-valuemax="{{ $max }}"
    aria-valuetext="{{ $valueText }}"
    {{ $attributes->merge(['class' => 'relative inline-flex items-center justify-center']) }}
    style="width: {{ $sizePx }}px; height: {{ $boxHeight }}px;"
>
    <svg
        data-slot="gauge-svg"
        class="overflow-visible"
        width="{{ $sizePx }}"
        height="{{ $sizePx }}"
        viewBox="0 0 {{ $sizePx }} {{ $sizePx }}"
        fill="none"
        aria-hidden="true"
        style="transform: rotate({{ $rotation }}deg);"
    >
        {{-- Track: the visible portion of the circle. --}}
        <circle
            data-slot="gauge-track"
            class="text-muted"
            cx="{{ $cx }}"
            cy="{{ $cy }}"
            r="{{ $r }}"
            stroke="currentColor"
            stroke-width="{{ $strokeW }}"
            stroke-linecap="round"
            stroke-dasharray="{{ $visibleLen }} {{ $circumference }}"
        />
        {{-- Progress: fraction of the visible portion. --}}
        <circle
            data-slot="gauge-indicator"
            class="{{ $colorClass }} transition-[stroke-dashoffset] duration-700 ease-out motion-reduce:transition-none"
            cx="{{ $cx }}"
            cy="{{ $cy }}"
            r="{{ $r }}"
            stroke="currentColor"
            stroke-width="{{ $strokeW }}"
            stroke-linecap="round"
            stroke-dasharray="{{ $progressLen }} {{ $circumference }}"
        />
    </svg>

    @if ($showValue)
        <span
            data-slot="gauge-value"
            class="pointer-events-none absolute inset-0 flex justify-center font-semibold tabular-nums text-foreground {{ $variant === 'semi' ? 'items-end pb-1' : 'items-center' }}"
            style="font-size: {{ max(12, (int) round($sizePx / 5)) }}px; line-height: 1;"
        >{{ $value }}</span>
    @endif
</div>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.2.1
Status
Stable
License
open
Accessibility reviewed
No review date recorded
Last breaking change
No date recorded
Deprecation
Not deprecated
Contract
v6
Foundation
≥ 1.0.0