Componentcharts0.9 KB gzipZero dependencies
Histogram
Frequency distribution histogram with hover count readout and grow animation.
Preview
Live Preview
4518:00
12019:00
8520:00
3021:00
6522:00
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add histogramOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { Histogram } from "@/components/ui/histogram";
<Histogram bins={[{ id: "1", label: "18:00", count: 45 }, { id: "2", label: "19:00", count: 120 }]} />Usage guidance
Use Histogram when a ticket stub surface needs Frequency distribution histogram with hover count readout and grow animation. Keep props minimal and prefer composition with sibling stubs.
Avoid Histogram for long form flows or dense data grids where a dedicated layout block fits better.
Source code
histogram.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 HistogramBin {
id: string;
label: string;
count: number;
}
export interface HistogramProps extends React.HTMLAttributes<HTMLDivElement> {
bins: HistogramBin[];
height?: number;
}
/** Frequency histogram chart: contiguous bars + tooltip hover. */
export function Histogram({ bins, height = 180, className, ...props }: HistogramProps) {
const max = Math.max(...bins.map((b) => b.count), 1);
const [hover, setHover] = React.useState<string | null>(null);
return (
<div className={cn("w-full max-w-md", className)} {...props}>
<style>{`@keyframes hgGrow { from { transform: scaleY(0); } }`}</style>
<div className="flex items-end" style={{ height }}>
{bins.map((bin, idx) => {
const h = (bin.count / max) * 100;
const isHover = hover === bin.id;
return (
<div
key={bin.id}
className="flex h-full flex-1 flex-col items-center justify-end"
onMouseEnter={() => setHover(bin.id)}
onMouseLeave={() => setHover(null)}
>
<span className={cn("mb-0.5 font-mono text-[9px] tabular-nums transition-opacity duration-150 motion-reduce:transition-none", isHover ? "opacity-100 text-accent" : "opacity-0")}>
{bin.count}
</span>
<div
className={cn(
"w-full border-x border-t border-border bg-accent/50 transition-colors duration-150 motion-reduce:transition-none",
isHover && "bg-accent"
)}
style={{
height: `${h}%`,
animation: "hgGrow 0.5s cubic-bezier(0.16,1,0.3,1) both",
animationDelay: `${idx * 40}ms`,
transformOrigin: "bottom",
}}
/>
<span className="mt-1 truncate font-mono text-[8px] text-muted-foreground">{bin.label}</span>
</div>
);
})}
</div>
</div>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| bins | HistogramBin[] | Array of bins with id, label and count |
| height | number | Chart height in pixels (default 180) |