Template · React · HTML
Health overview
A health dashboard in Tiles: three vital figures, a patient card, a score dial and calorie bars with macros.
Preview
React
Install the template with shadcn. It lands in your project as ordinary components that you edit yourself.
npx shadcn@latest add https://mikkelmanniche.dk/lab/r/health-overview.jsonnpx shadcn@latest add @manniche/health-overviewhealth-overview.tsx
// A health overview: three vital figures, a patient card, a score dial and calorie bars with macros.
import { cn } from '@/lib/utils'
import { BarChart, type BarPoint } from '@/registry/manniche/bar-chart/bar-chart'
import { BigNumber } from '@/registry/manniche/chart-kit/chart-kit'
import { DataTile, TileFact } from '@/registry/manniche/data-tile/data-tile'
import { Dial, type DialZone } from '@/registry/manniche/dial/dial'
import { Donut, type DonutDatum } from '@/registry/manniche/donut/donut'
export type HealthOverviewData = {
vitals: { id: string; title: string; value: number; unit: string }[]
patient: { name: string; details: { label: string; value: string }[] }
score: { title: string; value: number; zones: DialZone[]; caption: string }
calories: { title: string; points: BarPoint[]; macros: DonutDatum[]; macrosTitle: string }
}
export type HealthOverviewLabels = { note?: string }
export type HealthOverviewProps = { data: HealthOverviewData; labels?: HealthOverviewLabels; className?: string }
export function HealthOverview({ data, labels, className }: HealthOverviewProps) {
const note = labels?.note ?? 'Example data.'
return (
<div className={cn('@container w-full rounded-2xl bg-background p-3 text-foreground', className)}>
<div className="grid grid-cols-1 gap-3 @lg:grid-cols-3 @3xl:grid-cols-6">
{data.vitals.map((v) => (
<div key={v.id} className="@3xl:col-span-2">
<DataTile className="h-full" title={v.title} density="compact">
<TileFact aside={<span className="text-sm text-muted-foreground">{v.unit}</span>}>
<BigNumber value={v.value} size="lg" />
</TileFact>
</DataTile>
</div>
))}
<div className="@lg:col-span-3 @3xl:col-span-3">
<DataTile className="h-full" title={data.patient.name} inverted>
<dl className="grid grid-cols-2 gap-3 text-sm">
{data.patient.details.map((d) => (
<div key={d.label}>
<dt className="opacity-70">{d.label}</dt>
<dd className="font-medium">{d.value}</dd>
</div>
))}
</dl>
</DataTile>
</div>
<div className="@lg:col-span-3 @3xl:col-span-3">
<DataTile className="h-full" title={data.score.title} footer={note}>
<Dial value={data.score.value} min={0} max={100} zones={data.score.zones} label={data.score.title} caption={data.score.caption} />
</DataTile>
</div>
<div className="@lg:col-span-3 @3xl:col-span-4">
<DataTile className="h-full" title={data.calories.title} footer={note}>
<BarChart data={data.calories.points} label={data.calories.title} format={{ suffix: ' kcal' }} />
</DataTile>
</div>
<div className="@lg:col-span-3 @3xl:col-span-2">
<DataTile className="h-full" title={data.calories.macrosTitle} footer={note}>
<Donut data={data.calories.macros} label={data.calories.macrosTitle} format={{ suffix: ' g' }} />
</DataTile>
</div>
</div>
</div>
)
}health-overview-demo.tsx
import { HealthOverview, type HealthOverviewData } from '@/components/health-overview'
// Example data only. The person and all figures are invented; this is not medical information.
const data: HealthOverviewData = {
vitals: [
{ id: 'hr', title: 'Heart rate', value: 64, unit: 'bpm' },
{ id: 'sl', title: 'Sleep', value: 7, unit: 'hours' },
{ id: 'st', title: 'Steps', value: 8200, unit: 'today' },
],
patient: {
name: 'Sample Patient',
details: [
{ label: 'Age', value: '41' },
{ label: 'Height', value: '178 cm' },
{ label: 'Last visit', value: '2 Oct 2026' },
{ label: 'Plan', value: 'Example plan' },
],
},
score: {
title: 'Wellness score',
value: 74,
caption: 'example score',
zones: [
{ label: 'Low', to: 40 },
{ label: 'Fair', to: 70 },
{ label: 'Good', to: 100 },
],
},
calories: {
title: 'Calories, last 7 days',
points: ['Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue'].map((label, i) => ({ label, value: [2100, 1950, 2250, 2000, 2300, 2600, 1900][i] })),
macrosTitle: 'Macros today',
macros: [
{ label: 'Carbs', value: 240 },
{ label: 'Protein', value: 110 },
{ label: 'Fat', value: 70 },
],
},
}
export default function HealthOverviewDemo() {
return <HealthOverview data={data} />
}HTML
The whole page as one file with all CSS built in and no JavaScript. Toggles, tabs and filters work with HTML and CSS alone.
The colour in your own app
If you already have shadcn set up, these variables give the same colour. Light in :root, dark in .dark.
:root {
--primary: oklch(0.52 0.2 262);
--primary-foreground: oklch(0.99 0 0);
--accent: oklch(0.95 0.034 262);
--accent-foreground: oklch(0.36 0.140 262);
--ring: oklch(0.52 0.2 262);
}
.dark {
--primary: oklch(0.74 0.150 262);
--primary-foreground: oklch(0.18 0.024 262);
--accent: oklch(0.29 0.050 262);
--accent-foreground: oklch(0.9 0.050 262);
--ring: oklch(0.74 0.150 262);
}Install
npx shadcn@latest add https://mikkelmanniche.dk/lab/r/health-overview.json