dashboard-patterns
Dashboard UI patterns with widget composition, real-time data updates, responsive grid layouts, and data tables for React applications. Use when building dashboards, widgets, or data tables.
How do I install this agent skill?
npx skills add https://github.com/yonatangross/orchestkit --skill dashboard-patternsIs this agent skill safe to install?
- Gen Agent Trust Hubpass
The dashboard-patterns skill contains standard React UI components and patterns for building analytics dashboards. It uses industry-standard libraries for data fetching and table management and exhibits no malicious behavior or security vulnerabilities.
- Socketpass
No alerts
- Snykpass
Risk: LOW · No issues
What does this agent skill do?
Dashboard Patterns
Dashboard UI patterns for building admin panels, analytics dashboards, and data-driven interfaces with React.
Layout Patterns
Responsive Dashboard Grid
function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<div className="min-h-screen bg-muted/40">
<aside className="fixed inset-y-0 left-0 z-10 w-64 border-r bg-background">
<Sidebar />
</aside>
<main className="pl-64">
<header className="sticky top-0 z-10 border-b bg-background px-6 py-4">
<DashboardHeader />
</header>
<div className="p-6">
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">{children}</div>
</div>
</main>
</div>
);
}
function DashboardGrid() {
return (
<div className="grid gap-4 grid-cols-1 sm:grid-cols-2 lg:grid-cols-4">
<StatCard title="Revenue" value="$45,231" change="+12%" />
<StatCard title="Users" value="2,350" change="+5.2%" />
<StatCard title="Orders" value="1,245" change="+18%" />
<StatCard title="Conversion" value="3.2%" change="-0.4%" />
<div className="col-span-1 sm:col-span-2"><RevenueChart /></div>
<div className="col-span-1 sm:col-span-2"><TrafficChart /></div>
<div className="col-span-full"><RecentOrdersTable /></div>
</div>
);
}
Widget Components
Stat Card Widget
import { TrendingUp, TrendingDown } from 'lucide-react';
interface StatCardProps {
title: string;
value: string | number;
change?: string;
changeType?: 'positive' | 'negative' | 'neutral';
icon?: React.ReactNode;
}
function StatCard({ title, value, change, changeType = 'neutral', icon }: StatCardProps) {
return (
<div className="rounded-xl border bg-card p-6">
<div className="flex items-center justify-between">
<p className="text-sm font-medium text-muted-foreground">{title}</p>
{icon && <div className="text-muted-foreground">{icon}</div>}
</div>
<div className="mt-2 flex items-baseline gap-2">
<p className="text-3xl font-bold">{value}</p>
{change && (
<span className={cn(
'flex items-center text-sm font-medium',
changeType === 'positive' && 'text-green-600',
changeType === 'negative' && 'text-red-600',
)}>
{changeType === 'positive' && <TrendingUp className="h-4 w-4" />}
{changeType === 'negative' && <TrendingDown className="h-4 w-4" />}
{change}
</span>
)}
</div>
</div>
);
}
Widget Registry Pattern
type WidgetType = 'stat' | 'chart' | 'table' | 'list';
interface WidgetConfig {
id: string;
type: WidgetType;
title: string;
span?: number;
props: Record<string, unknown>;
}
const widgetRegistry: Record<WidgetType, React.ComponentType<any>> = {
stat: StatCard,
chart: ChartCard,
table: DataTable,
list: ListWidget,
};
function DashboardWidget({ config }: { config: WidgetConfig }) {
const Component = widgetRegistry[config.type];
if (!Component) return null;
return (
<div style={{ gridColumn: config.span ? `span ${config.span}` : undefined }}>
<Component title={config.title} {...config.props} />
</div>
);
}
Real-Time Data Patterns
TanStack Query + SSE
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { useEffect } from 'react';
function useRealtimeMetrics() {
const queryClient = useQueryClient();
const { data, isLoading } = useQuery({
queryKey: ['metrics'],
queryFn: fetchMetrics,
});
useEffect(() => {
const eventSource = new EventSource('/api/metrics/stream');
eventSource.onmessage = (event) => {
const update = JSON.parse(event.data);
queryClient.setQueryData(['metrics'], (old: Metrics | undefined) => ({
...old,
...update,
}));
};
eventSource.onerror = () => {
eventSource.close();
queryClient.invalidateQueries({ queryKey: ['metrics'] });
};
return () => eventSource.close();
}, [queryClient]);
return { data, isLoading };
}
Data Table (TanStack Table)
import {
useReactTable,
getCoreRowModel,
getSortedRowModel,
getFilteredRowModel,
getPaginationRowModel,
flexRender,
type ColumnDef,
type SortingState,
} from '@tanstack/react-table';
const columns: ColumnDef<Order>[] = [
{ accessorKey: 'id', header: 'Order ID' },
{ accessorKey: 'customer', header: 'Customer' },
{ accessorKey: 'amount', header: 'Amount', cell: ({ getValue }) => `$${getValue<number>().toLocaleString()}` },
{ accessorKey: 'status', header: 'Status', cell: ({ getValue }) => <StatusBadge status={getValue()} /> },
];
function OrdersTable({ data }: { data: Order[] }) {
const [sorting, setSorting] = useState<SortingState>([]);
const [globalFilter, setGlobalFilter] = useState('');
const table = useReactTable({
data,
columns,
state: { sorting, globalFilter },
onSortingChange: setSorting,
onGlobalFilterChange: setGlobalFilter,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});
return (
<div>
<input
value={globalFilter}
onChange={(e) => setGlobalFilter(e.target.value)}
placeholder="Search orders..."
className="mb-4 rounded border px-3 py-2"
/>
<table className="w-full">
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th key={header.id} onClick={header.column.getToggleSortingHandler()} className="cursor-pointer px-4 py-2 text-left">
{flexRender(header.column.columnDef.header, header.getContext())}
{header.column.getIsSorted() === 'asc' && ' ↑'}
{header.column.getIsSorted() === 'desc' && ' ↓'}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id} className="border-t">
{row.getVisibleCells().map((cell) => (
<td key={cell.id} className="px-4 py-2">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
<div className="mt-4 flex items-center gap-2">
<button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>Previous</button>
<span>Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}</span>
<button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>Next</button>
</div>
</div>
);
}
Skeleton Loading
function DashboardSkeleton() {
return (
<div className="grid gap-4 grid-cols-1 md:grid-cols-2 lg:grid-cols-4">
{[...Array(4)].map((_, i) => (
<div key={i} className="rounded-xl border bg-card p-6">
<div className="h-4 w-24 animate-pulse rounded bg-muted" />
<div className="mt-2 h-8 w-32 animate-pulse rounded bg-muted" />
</div>
))}
<div className="col-span-full rounded-xl border bg-card p-6">
<div className="mt-4 space-y-2">
{[...Array(5)].map((_, i) => (
<div key={i} className="h-12 animate-pulse rounded bg-muted" />
))}
</div>
</div>
</div>
);
}
Anti-Patterns (FORBIDDEN)
// NEVER: Fetch data in every widget independently (duplicated queries)
// NEVER: Re-render entire dashboard on single metric change
// NEVER: Hardcoded dashboard layout (not responsive)
// NEVER: Polling without intervals (infinite loop)
// NEVER: Missing loading states (flash of empty state)
// NEVER: Real-time updates without debounce (100 re-renders/sec)
Key Decisions
| Decision | Recommendation |
|---|---|
| Layout | CSS Grid for 2D dashboard layouts |
| Real-time | SSE for server->client, WebSocket for bidirectional |
| Data table | TanStack Table for features |
| State | TanStack Query with granular keys |
| Loading | Skeleton for content areas |
Related Skills
recharts-patterns- Chart components for dashboardstanstack-query-advanced- Data fetching patternsstreaming-api-patterns- SSE and WebSocket implementation
How can the creator link this skill?
Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.
<a href="https://skillzs.dev/skills/yonatangross/orchestkit/dashboard-patterns">View dashboard-patterns on skillZs</a>