# Dashboard 5

> Web analytics dashboard with visitors chart, live users, top pages, traffic sources, and Core Web Vitals.

A shadcn/ui block from the [@efferd](https://efferd.com/?utm_source=shadcn.exchange) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/efferd/dashboard-5).

- Page, with a live preview: https://shadcn.exchange/r/efferd/dashboard-5
- Screenshot: https://shadcn.exchange/shot/efferd/dashboard-5/light.png
- Registry item: https://efferd.com/r/dashboard-5.json
- Categories: dashboard
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcn.exchange/r/efferd/dashboard-5.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `badge`, `button`, `card`, `chart`, `table`, `tooltip`, `@efferd/app-shell-5`, `@efferd/formater`

## Files

### `registry/blocks/dashboard/5/audience-mix.tsx`

```tsx
"use client";

import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import {
	ShareBarList,
	ShareBarListContent,
	ShareBarListFill,
	ShareBarListItem,
	ShareBarListLabel,
	ShareBarListValue,
} from "@/components/share-bar-list";

const segments = [
	{ label: "Returning visitors", share: 54 },
	{ label: "New visitors", share: 41 },
	{ label: "Logged-in users", share: 5 },
] as const;

export function AudienceMix() {
	return (
		<Card className="dark:bg-transparent">
			<CardHeader className="border-b">
				<CardTitle className="text-balance">Audience mix</CardTitle>
				<CardDescription className="text-pretty">
					Session split by familiarity in the last 12 months.
				</CardDescription>
			</CardHeader>
			<CardContent className="p-0 py-1">
				<ShareBarList aria-label="Audience segments by share of sessions">
					{segments.map((row) => (
						<ShareBarListItem key={row.label} value={row.share}>
							<ShareBarListContent>
								<ShareBarListLabel>{row.label}</ShareBarListLabel>
								<ShareBarListValue>{row.share}%</ShareBarListValue>
							</ShareBarListContent>
							<ShareBarListFill />
						</ShareBarListItem>
					))}
				</ShareBarList>
			</CardContent>
		</Card>
	);
}
```

### `registry/blocks/dashboard/5/browser-share.tsx`

```tsx
"use client";

import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import {
	ShareBarList,
	ShareBarListContent,
	ShareBarListFill,
	ShareBarListItem,
	ShareBarListLabel,
	ShareBarListValue,
} from "@/components/share-bar-list";

const browsers = [
	{ label: "Chrome", share: 58 },
	{ label: "Safari", share: 22 },
	{ label: "Edge", share: 9 },
	{ label: "Firefox", share: 7 },
	{ label: "Other", share: 4 },
] as const;

export function BrowserShare() {
	return (
		<Card className="dark:bg-transparent">
			<CardHeader className="border-b">
				<CardTitle className="text-balance">Browsers</CardTitle>
				<CardDescription className="text-pretty">
					Share of sessions by primary browser family.
				</CardDescription>
			</CardHeader>
			<CardContent className="p-0 py-1">
				<ShareBarList aria-label="Sessions by browser">
					{browsers.map((row) => (
						<ShareBarListItem key={row.label} value={row.share}>
							<ShareBarListContent>
								<ShareBarListLabel>{row.label}</ShareBarListLabel>
								<ShareBarListValue>{row.share}%</ShareBarListValue>
							</ShareBarListContent>
							<ShareBarListFill />
						</ShareBarListItem>
					))}
				</ShareBarList>
			</CardContent>
		</Card>
	);
}
```

### `registry/blocks/dashboard/5/dashboard.tsx`

```tsx
import { AudienceMix } from "@/components/audience-mix";
import { BrowserShare } from "@/components/browser-share";
import { OnlineNow } from "@/components/online-now";
import { TopCountries } from "@/components/top-countries";
import { TopPages } from "@/components/top-pages";
import { TopReferrers } from "@/components/top-referrers";
import { TrafficSourcesChart } from "@/components/traffic-sources-chart";
import { VisitorsChart } from "@/components/visitors-chart";
import { WebVitals } from "@/components/web-vitals";

export function Dashboard() {
	return (
		<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
			<VisitorsChart />
			<OnlineNow />
			<TopPages />
			<TopCountries />
			<TrafficSourcesChart />
			<AudienceMix />
			<BrowserShare />
			<TopReferrers />
			<WebVitals />
		</div>
	);
}
```

### `registry/blocks/dashboard/5/online-now.tsx`

```tsx
"use client";

import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import {
	Tooltip,
	TooltipContent,
	TooltipTrigger,
} from "@/components/ui/tooltip";
import { Delta, DeltaIcon, DeltaValue } from "@/components/delta";
import { StatusIndicator } from "@/components/../../components/indicator";
import {
	ShareBarList,
	ShareBarListContent,
	ShareBarListFill,
	ShareBarListItem,
	ShareBarListLabel,
	ShareBarListValue,
} from "@/components/share-bar-list";

const devices = [
	{ label: "Mobile", share: 65 },
	{ label: "Desktop", share: 33 },
	{ label: "Tablet", share: 2 },
] as const;

export function OnlineNow() {
	return (
		<Card className="gap-0 pb-0 md:col-span-2 lg:col-span-1 dark:bg-transparent">
			<CardHeader className="flex flex-row items-start justify-between gap-3 border-b">
				<div className="flex min-w-0 flex-col gap-0">
					<CardTitle className="font-mono text-2xl tabular-nums">94</CardTitle>
					<CardDescription>
						<Tooltip>
							<TooltipTrigger asChild>
								<Button
									className={cn(
										"cursor-help px-1 py-px font-normal text-muted-foreground",
										"hover:underline-0"
									)}
									type="button"
									variant="link"
								>
									<StatusIndicator />
									<span>visitors online</span>
								</Button>
							</TooltipTrigger>
							<TooltipContent side="bottom">
								In the last 5 minutes.
							</TooltipContent>
						</Tooltip>
					</CardDescription>
				</div>
				<Delta value={14.8} variant="badge">
					<DeltaIcon variant="trend" />
					<DeltaValue suffix="%" />
				</Delta>
			</CardHeader>
			<CardContent
				className={cn("relative flex h-full items-center px-0 py-2")}
			>
				<ShareBarList>
					{devices.map((d) => (
						<ShareBarListItem key={d.label} value={d.share}>
							<ShareBarListContent>
								<ShareBarListLabel>{d.label}</ShareBarListLabel>
								<ShareBarListValue>{d.share}%</ShareBarListValue>
							</ShareBarListContent>
							<ShareBarListFill data-online-bar />
						</ShareBarListItem>
					))}
				</ShareBarList>
			</CardContent>
		</Card>
	);
}
```

### `registry/blocks/dashboard/5/share-bar-list.tsx`

```tsx
"use client";

import { cn } from "@/lib/utils";
import * as React from "react";

const BAR_COLOR = "var(--chart-2)";

type ShareBarListItemContextValue = {
	value: number;
};

const ShareBarListItemContext =
	React.createContext<ShareBarListItemContextValue | null>(null);

function useShareBarListItemContext(component: string) {
	const ctx = React.useContext(ShareBarListItemContext);
	if (!ctx) {
		throw new Error(
			`\`${component}\` must be used within \`ShareBarListItem\`.`
		);
	}
	return ctx;
}

function ShareBarList({ className, ...props }: React.ComponentProps<"ul">) {
	return (
		<ul
			className={cn(
				"relative z-10 my-auto flex w-full flex-col gap-0.5",
				className
			)}
			data-slot="share-bar-list"
			{...props}
		/>
	);
}

function ShareBarListItem({
	className,
	value,
	children,
	...props
}: React.ComponentProps<"li"> & { value: number }) {
	const clamped = Math.min(100, Math.max(0, value));
	const ctx = React.useMemo(
		() => ({ value: clamped }) satisfies ShareBarListItemContextValue,
		[clamped]
	);

	return (
		<ShareBarListItemContext.Provider value={ctx}>
			<li
				className={cn(
					"group relative flex h-12 items-center gap-2 overflow-hidden px-3",
					className
				)}
				data-slot="share-bar-list-item"
				{...props}
			>
				{children}
			</li>
		</ShareBarListItemContext.Provider>
	);
}

function ShareBarListContent({
	className,
	...props
}: React.ComponentProps<"div">) {
	return (
		<div
			className={cn(
				"z-10 flex w-full items-center justify-between gap-2 text-sm",
				className
			)}
			data-slot="share-bar-list-content"
			{...props}
		/>
	);
}

function ShareBarListLabel({
	className,
	...props
}: React.ComponentProps<"span">) {
	return (
		<span
			className={cn("text-pretty", className)}
			data-slot="share-bar-list-label"
			{...props}
		/>
	);
}

function ShareBarListValue({
	className,
	...props
}: React.ComponentProps<"span">) {
	return (
		<span
			className={cn("font-medium tabular-nums", className)}
			data-slot="share-bar-list-value"
			{...props}
		/>
	);
}

function ShareBarListFill({
	className,
	style,
	...props
}: React.ComponentProps<"div">) {
	const { value } = useShareBarListItemContext("ShareBarListFill");
	const borderMixPercent = Math.min(100, Math.max(36, value * 1.75));
	const borderRightColor = `color-mix(in srgb, ${BAR_COLOR} ${borderMixPercent}%, transparent)`;
	const fillStartColor = `color-mix(in srgb, ${BAR_COLOR} 4%, transparent)`;
	const fillEndColor = `color-mix(in srgb, ${BAR_COLOR} 36%, transparent)`;
	const backgroundImage = `linear-gradient(to right, ${fillStartColor}, ${fillEndColor})`;

	return (
		<div
			aria-hidden
			className={cn(
				"pointer-events-none absolute top-0 left-0 h-full border-r-2 border-solid",
				className
			)}
			data-slot="share-bar-list-fill"
			style={{
				...style,
				width: `${value}%`,
				borderRightColor,
				backgroundImage,
			}}
			{...props}
		/>
	);
}

export {
	ShareBarList,
	ShareBarListContent,
	ShareBarListFill,
	ShareBarListItem,
	ShareBarListLabel,
	ShareBarListValue,
};
```

### `registry/blocks/dashboard/5/top-countries.tsx`

```tsx
import { formatInteger } from "@/lib/formater";
import { Button } from "@/components/ui/button";
import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import {
	Table,
	TableBody,
	TableCaption,
	TableCell,
	TableHead,
	TableHeader,
	TableRow,
} from "@/components/ui/table";

const FLAGPACK_BASE = "https://flag.vercel.app";

const rows = [
	{ code: "US", visits: 6120, delta: 5.2 },
	{ code: "DE", visits: 2840, delta: 8.1 },
	{ code: "GB", visits: 1960, delta: -1.4 },
	{ code: "FR", visits: 1420, delta: 3.6 },
	{ code: "CA", visits: 1180, delta: 0.9 },
	{ code: "NL", visits: 890, delta: 12.2 },
] as const;

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

function flagUrl(countryCode: string) {
	return `${FLAGPACK_BASE}/s/${countryCode.toUpperCase()}.svg`;
}

export function TopCountries() {
	return (
		<Card className="relative md:col-span-2 dark:bg-transparent">
			<CardHeader>
				<CardTitle className="text-balance">Top countries</CardTitle>
				<CardDescription className="text-pretty">
					Top countries in the last 12 months.
				</CardDescription>
			</CardHeader>
			<CardContent className="mask-b-from-50% mask-b-to-100% p-0 pb-2">
				<Table className="border-t">
					<TableCaption className="sr-only">
						Top countries by visits with year-over-year change.
					</TableCaption>
					<TableHeader>
						<TableRow>
							<TableHead className="pl-6" scope="col">
								Country
							</TableHead>
							<TableHead className="text-end tabular-nums" scope="col">
								Visits
							</TableHead>
							<TableHead className="pr-6 text-end" scope="col">
								Change
							</TableHead>
						</TableRow>
					</TableHeader>
					<TableBody>
						{rows.map((row) => (
							<TableRow className="hover:bg-transparent" key={row.code}>
								<TableCell className="max-w-[220px] truncate pl-6 font-medium">
									<span className="inline-flex max-w-full items-center gap-2">
										<img
											alt={`Flag of ${row.code}`}
											className="h-3.5 w-5 shrink-0 rounded object-cover"
											height={14}
											src={flagUrl(row.code)}
											width={20}
										/>
										<span className="min-w-0 truncate text-xs">
											{regionNames.of(row.code) ?? row.code}
										</span>
									</span>
								</TableCell>
								<TableCell className="text-end text-muted-foreground text-xs tabular-nums">
									{formatInteger(row.visits)}
								</TableCell>
								<TableCell className="pr-6 text-end text-muted-foreground text-xs">
									<span className="tabular-nums">
										{row.delta > 0 ? "+" : ""}
										{row.delta}%
									</span>
								</TableCell>
							</TableRow>
						))}
					</TableBody>
				</Table>
			</CardContent>

			<div className="mask-t-from-30% absolute inset-x-0 bottom-0 flex h-1/5 items-center justify-center bg-background">
				<Button asChild className="relative" variant="ghost">
					<a href="#">
						View All
						<IconPlaceholder
							aria-hidden="true"
							hugeicons="ArrowRightIcon"
							lucide="ArrowRightIcon"
							phosphor="ArrowRightIcon"
							remixicon="RiArrowRightLine"
							tabler="IconArrowRight"
						/>
					</a>
				</Button>
			</div>
		</Card>
	);
}
```

### `registry/blocks/dashboard/5/top-pages.tsx`

```tsx
import { formatInteger } from "@/lib/formater";
import { Button } from "@/components/ui/button";
import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import {
	Table,
	TableBody,
	TableCaption,
	TableCell,
	TableHead,
	TableHeader,
	TableRow,
} from "@/components/ui/table";

const rows = [
	{ path: "/", visits: 18_420, delta: 4.1 },
	{ path: "/pricing", visits: 6280, delta: 12.4 },
	{ path: "/blog/product-updates", visits: 4110, delta: -2.0 },
	{ path: "/docs/getting-started", visits: 3920, delta: 6.8 },
	{ path: "/changelog", visits: 2150, delta: 0.4 },
] as const;

export function TopPages() {
	return (
		<Card className="relative md:col-span-2 dark:bg-transparent">
			<CardHeader>
				<CardTitle className="text-balance">Top pages</CardTitle>
				<CardDescription className="text-pretty">
					First page in session, ranked by visits.
				</CardDescription>
			</CardHeader>
			<CardContent className="mask-b-from-50% mask-b-to-100% p-0 pb-2">
				<Table className="border-t">
					<TableCaption className="sr-only">
						Top landing pages by visits with year-over-year change.
					</TableCaption>
					<TableHeader>
						<TableRow>
							<TableHead className="pl-6" scope="col">
								Path
							</TableHead>
							<TableHead className="text-end tabular-nums" scope="col">
								Visits
							</TableHead>
							<TableHead className="pr-6 text-end" scope="col">
								Change
							</TableHead>
						</TableRow>
					</TableHeader>
					<TableBody>
						{rows.map((row) => (
							<TableRow className="hover:bg-transparent" key={row.path}>
								<TableCell className="max-w-[200px] truncate pl-6 font-medium">
									<span className="w-max rounded border border-border bg-muted/50 px-1 py-px text-xs">
										{row.path}
									</span>
								</TableCell>
								<TableCell className="text-end text-muted-foreground text-xs tabular-nums">
									{formatInteger(row.visits)}
								</TableCell>
								<TableCell className="pr-6 text-end text-muted-foreground text-xs">
									<span className="tabular-nums">
										{row.delta > 0 ? "+" : ""}
										{row.delta}%
									</span>
								</TableCell>
							</TableRow>
						))}
					</TableBody>
				</Table>
			</CardContent>

			<div className="mask-t-from-30% absolute inset-x-0 bottom-0 flex h-1/5 items-center justify-center bg-background">
				<Button asChild className="relative" variant="ghost">
					<a href="#">
						View All
						<IconPlaceholder
							aria-hidden="true"
							hugeicons="ArrowRightIcon"
							lucide="ArrowRightIcon"
							phosphor="ArrowRightIcon"
							remixicon="RiArrowRightLine"
							tabler="IconArrowRight"
						/>
					</a>
				</Button>
			</div>
		</Card>
	);
}
```

### `registry/blocks/dashboard/5/top-referrers.tsx`

```tsx
import { formatInteger } from "@/lib/formater";
import { Button } from "@/components/ui/button";
import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import {
	Table,
	TableBody,
	TableCaption,
	TableCell,
	TableHead,
	TableHeader,
	TableRow,
} from "@/components/ui/table";

const rows = [
	{ host: "news.ycombinator.com", sessions: 1420 },
	{ host: "t.co", sessions: 980 },
	{ host: "github.com", sessions: 760 },
	{ host: "producthunt.com", sessions: 540 },
	{ host: "reddit.com", sessions: 410 },
] as const;

export function TopReferrers() {
	return (
		<Card className="relative dark:bg-transparent">
			<CardHeader>
				<CardTitle className="text-balance">Top referrers</CardTitle>
				<CardDescription className="text-pretty">
					External sites sending the most attributed sessions.
				</CardDescription>
			</CardHeader>
			<CardContent className="mask-b-from-50% mask-b-to-100% p-0 pb-2">
				<Table className="border-t">
					<TableCaption className="sr-only">
						Top referrer domains by attributed sessions.
					</TableCaption>
					<TableHeader>
						<TableRow>
							<TableHead className="pl-6" scope="col">
								Host
							</TableHead>
							<TableHead className="pr-6 text-end tabular-nums" scope="col">
								Sessions
							</TableHead>
						</TableRow>
					</TableHeader>
					<TableBody>
						{rows.map((row) => (
							<TableRow className="hover:bg-transparent" key={row.host}>
								<TableCell className="max-w-[220px] truncate pl-6 font-medium">
									<span className="text-xs">{row.host}</span>
								</TableCell>
								<TableCell className="pr-6 text-end text-muted-foreground text-xs tabular-nums">
									{formatInteger(row.sessions)}
								</TableCell>
							</TableRow>
						))}
					</TableBody>
				</Table>
			</CardContent>

			<div className="mask-t-from-30% absolute inset-x-0 bottom-0 flex h-1/5 items-center justify-center bg-background">
				<Button asChild className="relative" variant="ghost">
					<a href="#">
						View All
						<IconPlaceholder
							aria-hidden="true"
							hugeicons="ArrowRightIcon"
							lucide="ArrowRightIcon"
							phosphor="ArrowRightIcon"
							remixicon="RiArrowRightLine"
							tabler="IconArrowRight"
						/>
					</a>
				</Button>
			</div>
		</Card>
	);
}
```

### `registry/blocks/dashboard/5/traffic-sources-chart.tsx`

```tsx
"use client";

import { formatCompactNumber } from "@/lib/formater";
import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import {
	ShareBarList,
	ShareBarListContent,
	ShareBarListFill,
	ShareBarListItem,
	ShareBarListLabel,
	ShareBarListValue,
} from "@/components/share-bar-list";

const chartData = [
	{ source: "Organic search", sessions: 4120 },
	{ source: "Direct", sessions: 2890 },
	{ source: "Referral", sessions: 1640 },
	{ source: "Paid social", sessions: 980 },
	{ source: "Email", sessions: 620 },
] as const;

const maxSessions = Math.max(...chartData.map((d) => d.sessions));

function barWidthPercent(sessions: number) {
	if (maxSessions <= 0) {
		return 0;
	}
	return (sessions / maxSessions) * 75;
}

export function TrafficSourcesChart() {
	return (
		<Card className="dark:bg-transparent">
			<CardHeader className="border-b">
				<CardTitle className="text-balance">Sessions by source</CardTitle>
				<CardDescription className="text-pretty">
					Attributed sessions in the last 12 months.
				</CardDescription>
			</CardHeader>
			<CardContent className="p-0 py-1">
				<ShareBarList aria-label="Sessions by traffic source">
					{chartData.map((row) => (
						<ShareBarListItem
							key={row.source}
							value={barWidthPercent(row.sessions)}
						>
							<ShareBarListContent>
								<ShareBarListLabel>{row.source}</ShareBarListLabel>
								<ShareBarListValue>
									{formatCompactNumber(row.sessions)}
								</ShareBarListValue>
							</ShareBarListContent>
							<ShareBarListFill />
						</ShareBarListItem>
					))}
				</ShareBarList>
			</CardContent>
		</Card>
	);
}
```

### `registry/blocks/dashboard/5/visitors-chart.tsx`

```tsx
"use client";

import { useId } from "react";
import { Area, AreaChart, CartesianGrid, XAxis } from "recharts";
import { formatInteger } from "@/lib/formater";
import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import {
	type ChartConfig,
	ChartContainer,
	ChartTooltip,
	ChartTooltipContent,
} from "@/components/ui/chart";
import { Delta, DeltaIcon, DeltaValue } from "@/components/delta";

const chartData = [
	{ month: "January", visitors: 555 },
	{ month: "February", visitors: 904 },
	{ month: "March", visitors: 727 },
	{ month: "April", visitors: 801 },
	{ month: "May", visitors: 942 },
	{ month: "June", visitors: 1048 },
	{ month: "July", visitors: 702 },
	{ month: "August", visitors: 1103 },
	{ month: "September", visitors: 879 },
	{ month: "October", visitors: 1046 },
	{ month: "November", visitors: 1407 },
	{ month: "December", visitors: 548 },
];

const totalVisitors = chartData.reduce((sum, row) => sum + row.visitors, 0);

const chartConfig = {
	visitors: {
		label: "Visitors",
		color: "var(--chart-2)",
	},
} satisfies ChartConfig;

export function VisitorsChart() {
	const gradientId = `visitors-area-${useId().replace(/:/g, "")}`;

	return (
		<Card className="md:col-span-2 lg:col-span-3 dark:bg-transparent">
			<CardHeader className="flex flex-row items-start justify-between">
				<div className="flex flex-col gap-1.5">
					<CardTitle className="font-mono text-2xl tabular-nums">
						{formatInteger(totalVisitors)}
					</CardTitle>
					<CardDescription className="text-pretty">
						Total visitors in the last 12 months.
					</CardDescription>
				</div>
				<Delta value={7.2} variant="badge">
					<DeltaIcon variant="trend" />
					<DeltaValue suffix="%" />
					<span>vs prior 12 months</span>
				</Delta>
			</CardHeader>
			<CardContent>
				<ChartContainer
					className="aspect-auto h-60 w-full"
					config={chartConfig}
				>
					<AreaChart
						accessibilityLayer
						data={chartData}
						margin={{
							left: 12,
							right: 12,
						}}
					>
						<defs>
							<linearGradient id={gradientId} x1="0" x2="0" y1="0" y2="1">
								<stop
									offset="0%"
									stopColor="var(--color-visitors)"
									stopOpacity={0.35}
								/>
								<stop
									offset="100%"
									stopColor="var(--color-visitors)"
									stopOpacity={0}
								/>
							</linearGradient>
						</defs>
						<CartesianGrid vertical={false} />
						<XAxis
							axisLine={false}
							dataKey="month"
							tickFormatter={(value) => String(value).slice(0, 3)}
							tickLine={false}
							tickMargin={8}
						/>
						<ChartTooltip
							content={<ChartTooltipContent indicator="dashed" />}
							cursor={{
								stroke: "var(--color-visitors)",
								strokeDasharray: "3 3",
								strokeLinecap: "round",
							}}
							wrapperStyle={{ outline: "none" }}
						/>
						<Area
							dataKey="visitors"
							dot={{
								fill: "var(--color-visitors)",
								r: 2.5,
								strokeWidth: 2,
							}}
							fill={`url(#${gradientId})`}
							isAnimationActive={false}
							name={chartConfig.visitors.label}
							stroke="var(--color-visitors)"
							strokeWidth={2}
							type="linear"
						/>
					</AreaChart>
				</ChartContainer>
			</CardContent>
		</Card>
	);
}
```

### `registry/blocks/dashboard/5/web-vitals.tsx`

```tsx
import {
	Card,
	CardContent,
	CardDescription,
	CardHeader,
	CardTitle,
} from "@/components/ui/card";
import { Delta, DeltaIcon, DeltaValue } from "@/components/delta";

const vitals = [
	{
		label: "LCP",
		name: "Largest Contentful Paint",
		value: "1.9s",
		delta: 120,
		deltaLabel: "faster vs prior month",
		suffix: "ms",
	},
	{
		label: "INP",
		name: "Interaction to Next Paint",
		value: "142ms",
		delta: 18,
		deltaLabel: "faster vs prior month",
		suffix: "ms",
	},
	{
		label: "CLS",
		name: "Cumulative Layout Shift",
		value: "0.04",
		delta: 0.07,
		deltaLabel: "lower vs prior month",
		suffix: "",
	},
] as const;

export function WebVitals() {
	return (
		<Card className="md:col-span-2 lg:col-span-4 dark:bg-transparent">
			<CardHeader className="border-b">
				<CardTitle className="text-balance">Core Web Vitals</CardTitle>
				<CardDescription className="text-pretty">
					Field experience on real sessions, measured at the origin.
				</CardDescription>
			</CardHeader>
			<CardContent>
				<ul className="grid gap-6 sm:grid-cols-3">
					{vitals.map((v) => (
						<li className="flex flex-col gap-1" key={v.label}>
							<p className="text-pretty font-medium text-sm">{v.label}</p>
							<p className="text-pretty text-muted-foreground text-xs">
								{v.name}
							</p>
							<p className="text-balance font-semibold text-2xl tabular-nums">
								{v.value}
							</p>
							<div className="flex items-center gap-1.5 text-pretty text-muted-foreground text-xs">
								<Delta value={v.delta} variant="default">
									<DeltaIcon />
									<DeltaValue suffix={v.suffix} />
								</Delta>
								<span>{v.deltaLabel}</span>
							</div>
						</li>
					))}
				</ul>
			</CardContent>
		</Card>
	);
}
```

### `registry/blocks/dashboard/delta.tsx`

```tsx
"use client";
import { cn } from "@/lib/utils";
import * as React from "react";
import { Badge } from "@/components/ui/badge";

type DeltaIconVariant = "default" | "trend" | "arrow";
type DeltaVariant = "default" | "badge";

type DeltaContextValue = {
	value: number;
};

const DeltaContext = React.createContext<DeltaContextValue | null>(null);

function useDeltaValue() {
	const context = React.useContext(DeltaContext);

	if (!context) {
		throw new Error(
			"DeltaIcon and DeltaValue must be used inside a `Delta` component."
		);
	}

	return context.value;
}

function Delta({
	className,
	value,
	variant = "default",
	...props
}: React.ComponentProps<"div"> & {
	value: number;
	variant?: DeltaVariant;
}) {
	return (
		<DeltaContext.Provider value={{ value }}>
			{variant === "badge" ? (
				<Badge
					className={cn(
						"gap-1 border-none tabular-nums [&_svg]:size-4 [&_svg]:shrink-0",
						value > 0
							? "bg-emerald-500/10 text-emerald-500"
							: "bg-red-500/10 text-red-500",
						className
					)}
					data-slot="delta"
					variant="secondary"
					{...(props as React.ComponentProps<typeof Badge>)}
				/>
			) : (
				<div
					className={cn(
						"inline-flex items-center gap-1 text-muted-foreground tabular-nums",
						"[&_svg]:size-3 [&_svg]:shrink-0",
						value > 0 ? "text-emerald-600 dark:text-emerald-400" : "",
						value < 0 ? "text-rose-600 dark:text-rose-400" : "",
						className
					)}
					data-slot="delta"
					{...props}
				/>
			)}
		</DeltaContext.Provider>
	);
}

function FilledShell({
	value,
	children,
}: {
	value: number;
	children: React.ReactNode;
}) {
	return (
		<span
			className={cn(
				"inline-flex size-3 shrink-0 items-center justify-center rounded-full",
				"[&_svg]:size-2! [&_svg]:shrink-0 [&_svg]:stroke-3! [&_svg]:text-background",
				value > 0 && "bg-emerald-500",
				value < 0 && "bg-red-500",
				(!value || value === 0) && "bg-muted-foreground"
			)}
			data-slot="delta-icon"
		>
			{children}
		</span>
	);
}

function DeltaIcon({
	variant = "default",
	filled = false,
	className,
	...props
}: Omit<React.ComponentProps<"svg">, "fill"> & {
	variant?: DeltaIconVariant;
	filled?: boolean;
}) {
	const resolvedValue = useDeltaValue();

	const mergedClassName = cn(className);

	const shell = (node: React.ReactElement) =>
		filled ? <FilledShell value={resolvedValue}>{node}</FilledShell> : node;

	const slotProps = filled ? {} : { "data-slot": "delta-icon" as const };

	if (!resolvedValue || resolvedValue === 0) {
		return shell(
			<IconPlaceholder
				{...slotProps}
				className={mergedClassName}
				hugeicons="MinusSignIcon"
				lucide="MinusIcon"
				phosphor="MinusIcon"
				remixicon="RiSubtractLine"
				tabler="IconMinus"
				{...props}
			/>
		);
	}

	if (resolvedValue > 0) {
		if (variant === "trend") {
			return shell(
				<IconPlaceholder
					{...slotProps}
					className={mergedClassName}
					hugeicons="TradeUpIcon"
					lucide="TrendingUpIcon"
					phosphor="TrendUpIcon"
					remixicon="RiArrowRightUpLine"
					tabler="IconTrendingUp"
					{...props}
				/>
			);
		}

		if (variant === "arrow") {
			return shell(
				<IconPlaceholder
					{...slotProps}
					className={mergedClassName}
					hugeicons="ArrowUp02Icon"
					lucide="ArrowUpIcon"
					phosphor="ArrowUpIcon"
					remixicon="RiArrowUpLine"
					tabler="IconArrowUp"
					{...props}
				/>
			);
		}

		return shell(
			<IconPlaceholder
				{...slotProps}
				className={mergedClassName}
				hugeicons="ArrowUp01Icon"
				lucide="ChevronUpIcon"
				phosphor="CaretUpIcon"
				remixicon="RiArrowUpSLine"
				tabler="IconChevronUp"
				{...props}
			/>
		);
	}

	if (variant === "trend") {
		return shell(
			<IconPlaceholder
				{...slotProps}
				className={mergedClassName}
				hugeicons="TradeDownIcon"
				lucide="TrendingDownIcon"
				phosphor="TrendDownIcon"
				remixicon="RiArrowRightDownLine"
				tabler="IconTrendingDown"
				{...props}
			/>
		);
	}

	if (variant === "arrow") {
		return shell(
			<IconPlaceholder
				{...slotProps}
				className={mergedClassName}
				hugeicons="ArrowDown02Icon"
				lucide="ArrowDownIcon"
				phosphor="ArrowDownIcon"
				remixicon="RiArrowDownLine"
				tabler="IconArrowDown"
				{...props}
			/>
		);
	}

	return shell(
		<IconPlaceholder
			{...slotProps}
			className={mergedClassName}
			hugeicons="ArrowDown01Icon"
			lucide="ChevronDownIcon"
			phosphor="CaretDownIcon"
			remixicon="RiArrowDownSLine"
			tabler="IconChevronDown"
			{...props}
		/>
	);
}

function DeltaValue({
	className,
	precision = 1,
	suffix = "%",
	absolute = true,
	...props
}: React.ComponentProps<"span"> & {
	precision?: number;
	suffix?: string;
	absolute?: boolean;
}) {
	const resolvedValue = useDeltaValue();

	const formattedValue = (
		absolute ? Math.abs(resolvedValue) : resolvedValue
	).toFixed(precision);

	return (
		<span
			className={cn("tabular-nums", className)}
			data-slot="delta-value"
			{...props}
		>
			{formattedValue}
			{suffix}
		</span>
	);
}
export { Delta, DeltaIcon, DeltaValue };
```
