Componentmedia0.9 KB gzipZero dependencies
Boss Bar
Encounter header with phase ticks and drain track.
Preview
Live Preview
Gatekeeper Golem
820 / 1000
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add boss-barOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { BossBar } from "@/components/ui/boss-bar";
<BossBar name="Gatekeeper Golem" value={820} max={1000} phases={3} />Usage guidance
Use Boss Bar when a ticket stub surface needs Encounter header with phase ticks and drain track. Keep props minimal and prefer composition with sibling stubs.
Avoid Boss Bar for long form flows or dense data grids where a dedicated layout block fits better.
Source code
boss-bar.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface BossBarProps extends React.HTMLAttributes<HTMLDivElement> {
name: string;
value: number;
max?: number;
phases?: number;
}
/** Boss bar: wide encounter header with phase ticks and draining health track. */
export function BossBar({ name, value, max = 1000, phases = 3, className, ...props }: BossBarProps) {
const pct = Math.max(0, Math.min(100, (value / Math.max(1, max)) * 100));
return (
<div className={cn("w-full select-none", className)} {...props}>
<style>{`@keyframes bossSweep { from { opacity: 0.2; } to { opacity: 1; } }`}</style>
<p className="text-center font-mono text-xs font-black uppercase tracking-[0.25em] text-foreground">
{name}
</p>
<div
role="progressbar"
aria-valuemin={0}
aria-valuemax={max}
aria-valuenow={Math.max(0, Math.min(max, value))}
aria-label={`${name} health`}
className="relative mt-1.5 h-11 overflow-hidden rounded-md border-2 border-destructive/70 bg-card p-1"
>
<div className="relative h-full w-full overflow-hidden rounded-[3px] bg-secondary">
<div
className="h-full bg-destructive transition-[width] duration-300 animate-[bossSweep_0.4s_ease-out] motion-reduce:animate-none motion-reduce:transition-none"
style={{ width: `${pct}%` }}
/>
{phases > 1 &&
Array.from({ length: phases - 1 }).map((_, i) => (
<span
key={i}
aria-hidden="true"
className="absolute inset-y-0 w-0.5 bg-card"
style={{ left: `${((i + 1) / phases) * 100}%` }}
/>
))}
</div>
</div>
<p className="mt-1 text-center font-mono text-[10px] tabular-nums text-muted-foreground" role="status">
{Math.max(0, value)} / {max}
</p>
</div>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| name | string | Encounter title (required). |
| value | number | Current boss health (required). |
| max | number | Maximum boss health (default 1000). |
| phases | number | Phase tick count (default 3). |