Admin Dashboard
Drop-in admin overview composition — PageHeader, responsive stat grid, optional secondary region, and ActivityFeed with empty-state fallback.
Preview
Dashboard
A live snapshot of your workspace — metrics, activity, and anything else worth a glance.
Total revenue
$48,120
Active users
2,847
Conversion rate
4.82%
Churn
1.2%
Recent activity
View all- New subscriptionJane Cooper
Acme Corp upgraded to the Team plan.
- User invitedWade Warren
dev@initech.example was invited to the workspace.
- Payment receivedSystem
$1,240.00 from Stark Industries.
- Report exportedEsther Howard
Q1 revenue report exported as CSV.
Installation
npx visor add --block admin-dashboardThis copies files into your project:
blocks/admin-dashboard/admin-dashboard.tsx— the block componentblocks/admin-dashboard/admin-dashboard.module.css— the styles
The registry pulls in page-header, stat-card, activity-feed, and empty-state as dependencies.
Usage
'use client';
import { AdminDashboard } from '@/blocks/admin-dashboard/admin-dashboard';
import { Button } from '@/components/ui/button/button';
export default function DashboardPage() {
return (
<AdminDashboard
eyebrow="Overview"
title="Dashboard"
description="A live snapshot of your workspace."
actions={<Button>New report</Button>}
stats={[
{
id: 'revenue',
label: 'Total revenue',
value: '$48,120',
delta: { value: '+12.4%', direction: 'up', label: 'vs last month' },
variant: 'highlight',
},
{
id: 'active-users',
label: 'Active users',
value: '2,847',
delta: { value: '+3.1%', direction: 'up' },
},
]}
activities={[
{
id: '1',
title: 'New subscription',
description: 'Acme Corp upgraded to the Team plan.',
actor: 'Jane Cooper',
timestamp: '2 minutes ago',
},
]}
activityViewAllHref="/admin/activity"
/>
);
}Drop this inside an AdminShell to get the full chrome — sidebar, topbar, and dashboard content in one composition.
Layout
The block is a vertical stack with consistent spacing:
- PageHeader — title, optional eyebrow, optional description, optional actions slot.
- Stat grid — responsive grid of StatCards. Driven by container queries: 1 column narrow, 2 columns at 36rem, 3 columns at 56rem, 4 columns at 72rem.
- Secondary region (optional) — a free-form slot for charts, announcements, or other widgets.
- Activity section — a
<section aria-labelledby>with a title, optional "View all" link, and an ActivityFeed. Falls back to a subtle EmptyState whenactivitiesis empty.
Because the block uses container queries on its own root, it adapts to whatever column width the surrounding AdminShell hands it — no global breakpoints involved.
Empty State
If activities.length === 0, the block renders a default <EmptyState> with a "No recent activity" message. Pass your own activityEmptyState ReactNode to override it entirely.
Accessibility
- The activity section is a semantic
<section>witharia-labelledbypointing at the generated heading. - The activity heading is a level-2
<h2>— assumes the PageHeader title is the page's<h1>. - The "View all" link has a tokenized focus ring.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | Required. Page title rendered in the PageHeader. |
eyebrow | ReactNode | — | Optional small uppercase label above the title. |
description | ReactNode | — | Optional supporting copy below the title. |
actions | ReactNode | — | Optional actions slot on the right side of the header. |
stats | AdminDashboardStat[] | [] | Stat cards rendered in the responsive grid. |
activityTitle | ReactNode | "Recent activity" | Heading rendered above the activity feed. |
activities | AdminDashboardActivity[] | [] | Activity events rendered in the feed. |
activityViewAllHref | string | — | If provided, renders a "View all" link in the activity section header. |
activityEmptyState | ReactNode | Default EmptyState | Replaces the default EmptyState when activities is empty. |
activityVariant | "default" | "compact" | "timeline" | "default" | Variant forwarded to the underlying ActivityFeed. |
secondaryRegion | ReactNode | — | Optional region rendered below the stat grid and above the activity feed. |
titleAs | "h1" | "h2" | "h3" | "h1" | Heading level used for the PageHeader title. |
className | string | — | Additional CSS class on the root element. |
AdminDashboardStat
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | Required. Unique key for React list reconciliation. |
label | ReactNode | — | Required. Stat label text. |
value | ReactNode | — | Required. Stat value. |
delta | StatCardDelta | — | Optional change indicator (value + direction). |
trend | ReactNode | — | Optional trend visualization (sparkline, icon). |
variant | "default" | "highlight" | "default" | Visual variant. |
size | "sm" | "md" | "md" | Card size. |
AdminDashboardActivity
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | — | Required. Unique key for React list reconciliation. |
leading | ReactNode | — | Optional leading element (avatar, icon). |
title | ReactNode | — | Required. Activity title. |
description | ReactNode | — | Optional detail text. |
actor | ReactNode | — | Optional actor name/element. |
timestamp | ReactNode | — | Required. When the activity occurred. |
trailing | ReactNode | — | Optional trailing element (action button, badge). |
About Blocks
Blocks are complete UI patterns made up of multiple Visor components. Unlike individual components, blocks represent larger, composed sections of UI — such as admin shells, login forms, or dashboard panels.
Blocks are copy-and-own, just like components. Install them into your project and customize freely.