Goal Card
A goal card pairing a current-vs-target readout with a token-themed progress bar, status badge and deadline.
Preview
<div class="mx-auto grid w-full max-w-2xl gap-4 sm:grid-cols-2">
<x-ui.goal-card
category="Revenue"
title="Monthly recurring revenue"
:current="32"
:target="50"
unit="k"
prefix="$"
deadline="Ends 30 Jun"
tone="default"
href="#"
/>
<x-ui.goal-card
category="Growth"
title="New activated workspaces"
:current="940"
:target="1000"
unit=""
prefix=""
deadline="Ends 30 Jun"
tone="success"
href="#"
/>
</div>
Installation
php artisan ui:add goal-card
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.
# Brok UI: Goal Card (`goal-card`)
A goal card pairing a current-vs-target readout with a token-themed progress bar, status badge and deadline.
Brok UI is a Laravel Blade component registry. Installed components are plain Blade files the app owns.
## Install
```bash
php artisan ui:add goal-card
```
## Usage
```blade
<div class="mx-auto grid w-full max-w-2xl gap-4 sm:grid-cols-2">
<x-ui.goal-card
category="Revenue"
title="Monthly recurring revenue"
:current="32"
:target="50"
unit="k"
prefix="$"
deadline="Ends 30 Jun"
tone="default"
href="#"
/>
<x-ui.goal-card
category="Growth"
title="New activated workspaces"
:current="940"
:target="1000"
unit=""
prefix=""
deadline="Ends 30 Jun"
tone="success"
href="#"
/>
</div>
```
## Props
- `title` (string, default `Monthly recurring revenue`)
- `category` (string, default `Revenue`)
- `current` (int, default `32`)
- `target` (int, default `50`)
- `unit` (string, default `k`)
- `prefix` (string, default `$`)
- `deadline` (string, default `Ends 30 Jun`)
- `tone` (string, default `default`)
- `href` (mixed|null, default `null`)
- `ctaLabel` (string, default `View details`)
## Use when
- Use when self-contained content objects benefit from a recognizable card-like presentation with local actions or metadata.
- Tracking one metric against a target with a progress bar and deadline.
- Summarising OKRs or KPIs in a dashboard grid.
## Avoid when
- Do not use card widgets where a simpler list, table, or plain text block would make comparison faster.
- Showing a value with no target; stat is the simpler readout.
- Charting a series over time; sparkline or chart carry the trend.
## Anti-patterns
- Using cards for dense cross-item comparison
## Rules
- Use the `<brok:goal-card>` tag (or `<x-ui.goal-card>`) 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/goal-card
- Registry JSON (files, props, contract): https://brokui.dev/r/open/goal-card.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | Monthly recurring revenue | |
| category | string | Revenue | |
| current | int | 32 | |
| target | int | 50 | |
| unit | string | k | |
| prefix | string | $ | |
| deadline | string | Ends 30 Jun | |
| tone | string | default | |
| href | mixed | null | null | |
| ctaLabel | string | View details |
Slots
default—
Data slots
Stable hooks for CSS overrides and browser tests.
Behavior
- current, target, unit and prefix compose the readout; the percentage is computed and drives the badge variant.
- tone colours the progress bar, and href adds a call to action labelled by ctaLabel.
- Declares registry capability flags: a11y, responsive, rtl, darkMode, localized.
Guidance
Present a self-contained content object with local context.
Use when
- Use when self-contained content objects benefit from a recognizable card-like presentation with local actions or metadata.
- Tracking one metric against a target with a progress bar and deadline.
- Summarising OKRs or KPIs in a dashboard grid.
Avoid when
- Do not use card widgets where a simpler list, table, or plain text block would make comparison faster.
- Showing a value with no target; stat is the simpler readout.
- Charting a series over time; sparkline or chart carry the trend.
Use instead
- List for compact scanning
- Table for exact comparison
Anti-patterns
- Using cards for dense cross-item comparison
- Anatomy
- Theming hooks
Accessibility
- Keyboard
- No component-owned keyboard interaction; native element behavior applies.
- Focus
none
- The progress bar is the progress primitive with an accessible name built from the title.
- The percentage is stated as text in the badge, so it does not depend on reading the bar.
- Semantic HTML and a stable
data-slotattribute for styling and scripting hooks. - Focus-visible rings use the
ringtoken, 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 underdir="rtl"— flip the preview to RTL to confirm. - Dark mode uses the same semantic tokens under the
darkclass; high contrast follows forced-color system tokens.
Livewire
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.
@props([
'title' => 'Monthly recurring revenue',
'category' => 'Revenue',
'current' => 32,
'target' => 50,
'unit' => 'k',
'prefix' => '$',
'deadline' => 'Ends 30 Jun',
'tone' => 'default',
'href' => null,
'ctaLabel' => 'View details',
])
@php
$current = (float) $current;
$target = (float) $target;
$pct = $target > 0 ? (int) round(min($current / $target, 1) * 100) : 0;
$complete = $target > 0 && $current >= $target;
// Progress tone is validated by the progress primitive; mirror the set here
// only to colour the completion badge.
$badgeVariant = match (true) {
$complete => 'success',
$tone === 'warning' => 'warning',
$tone === 'destructive' => 'destructive',
default => 'secondary',
};
@endphp
{{--
Goal card — an objective with a progress meter. The header pairs the goal
title with a category badge; a large current/target readout sits above the
token-themed progress bar (delegated to the progress primitive); a footer
carries the deadline and an optional details action. Values are coerced to
numbers and clamped so the bar never overflows.
--}}
<div
data-slot="goal-card"
{{ $attributes->merge(['class' => 'flex flex-col rounded-lg border border-border bg-card p-6 text-foreground shadow-sm']) }}
>
<div class="flex items-start justify-between gap-3">
<div class="min-w-0">
@if ($category)
<p class="text-xs font-medium uppercase tracking-wide text-muted-foreground">{{ $category }}</p>
@endif
<h3 class="mt-1 truncate text-sm font-semibold">{{ $title }}</h3>
</div>
<x-ui.badge :variant="$badgeVariant" size="sm" class="shrink-0">{{ $pct }}%</x-ui.badge>
</div>
<div class="mt-4 flex items-baseline gap-2">
<span class="text-2xl font-bold tracking-tight">{{ $prefix }}{{ rtrim(rtrim(number_format($current, 1), '0'), '.') }}{{ $unit }}</span>
<span class="text-sm text-muted-foreground">/ {{ $prefix }}{{ rtrim(rtrim(number_format($target, 1), '0'), '.') }}{{ $unit }}</span>
</div>
<x-ui.progress
:value="$pct"
:tone="$tone"
class="mt-3"
:aria-label="__(':title progress', ['title' => $title])"
/>
@if ($deadline || $href)
<div class="mt-4 flex items-center justify-between gap-3">
@if ($deadline)
<span class="inline-flex items-center gap-2 text-xs text-muted-foreground">
<svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" class="size-4">
<circle cx="12" cy="12" r="9" />
<path d="M12 7v5l3 2" />
</svg>
{{ $deadline }}
</span>
@else
<span></span>
@endif
@if ($href)
<x-ui.button :href="$href" size="sm" variant="ghost" with-arrow class="shrink-0">{{ __($ctaLabel) }}</x-ui.button>
@endif
</div>
@endif
</div>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.0.4 - 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