caliper uidocs

Page parts

Block

Dashboard, password reset and verification screens.

Installs components/ui/page-parts.tsxDepends on @radix-ui/react-slot, lucide-reactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/page-parts.json

Overview

How the product is doing this month.

Compared with the previous 30 days
  • Visits18,2408.2%up, good vs previous period
  • Sign-ups6124.1%up, good vs previous period
  • Conversion3.4%0.3%down, worse vs previous period
  • Revenue$42.1k11.6%up, good vs previous period
Visits and sign-ups
Visits and sign-ups
PointVisitsSign-upsEvent
Oct 894771
Oct 9111579
Oct 10105783
Oct 11114777
Oct 12106787
Oct 13113291
Oct 14124993
Oct 15131899
Oct 16125391
Oct 17131693
Oct 18142095
Oct 191422102
Oct 201453108
Oct 211576117

When to use #

Use it for

  • Building common application pages quickly.

Skip it when

  • You need a custom layout.

Installation #

terminal
pnpm dlx shadcn@latest add https://caliperui.site/r/page-parts.json

Adds its 11 files to components/ui/, each with its own stylesheet, and installs their packages. No account needed. The first part also adds Caliper UI’s tokens; import them once as in Installation.

Usage #

This is the code behind the preview above. It is built from DashboardLayout, ForgotPassword, VerifyEmail, WaitlistPage, StatusPage, OnboardingWizard, TeamGrid and JobBoard.

example.tsx
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { DashboardLayout } from "@/components/ui/page-parts"
import { LineChart } from "@/components/ui/line-chart"
import { MetricsDashboard } from "@/components/ui/metrics-dashboard"

const rng = (seed: number) => { let s = seed; return () => ((s = (s * 1664525 + 1013904223) % 4294967296) / 4294967296); };

export function PagePartsDemo() {
  const [range, setRange] = useState("30d");
  const r = rng(3);
  const data = Array.from({ length: 14 }, (_, i) => ({ id: `d${i}`, label: `Oct ${i + 8}`, values: { visits: Math.round(900 + i * 40 + r() * 200), signups: Math.round(60 + i * 3 + r() * 20) } }));
  const spark = (n: number) => Array.from({ length: 12 }, (_, i) => n * (0.8 + i * 0.02 + r() * 0.1));
  return (
    <DashboardLayout title="Overview" description="How the product is doing this month." actions={<Button size="sm">Export</Button>}
      kpis={<MetricsDashboard range={range} onRangeChange={setRange} metrics={[{ id: "a", label: "Visits", value: "18,240", delta: 8.2, series: spark(100) }, { id: "b", label: "Sign-ups", value: "612", delta: 4.1, series: spark(100) }, { id: "c", label: "Conversion", value: "3.4%", delta: -0.3, series: spark(100) }, { id: "d", label: "Revenue", value: "$42.1k", delta: 11.6, series: spark(100) }]} />}
      main={<LineChart label="Visits and sign-ups" data={data} series={[{ id: "visits", label: "Visits" }, { id: "signups", label: "Sign-ups" }]} />}
      aside={<><div className="grid gap-2 rounded-xl border border-border p-4"><h4 className="text-sm font-semibold">Recent activity</h4><ul className="grid gap-2 text-sm text-muted-foreground"><li>Maya upgraded to Team</li><li>Ravi invited 3 people</li><li>A webhook was retried</li><li>Noor published a dashboard</li></ul></div></>} />
  );
}

API reference #

DashboardLayout

component
PropTypeDefault
title *string—
descriptionstring—
actionsReactNode—
kpisReactNode—
main *ReactNode—
asideReactNode—
classNamestring—

ForgotPassword

component
PropTypeDefault
onSubmit *(email: string) => Promise<void>—
backHrefstring"#"
classNamestring—

VerifyEmail

component
PropTypeDefault
email *string—
onVerify *(code: string) => Promise<boolean>—
onResend *() => Promise<void>—
waitnumber30
classNamestring—

WaitlistPage

component
PropTypeDefault
title *string—
description *string—
onJoin *(email: string) => Promise<{ position: number; link: string; total: number; }>—
classNamestring—

StatusPage

component
PropTypeDefault
services *readonly ServiceStatus[]—
incidents *readonly Incident[]—
onSubscribe((email: string) => Promise<void>)—
classNamestring—

OnboardingWizard

component
PropTypeDefault
steps *readonly (OnboardingStep & { optional?: boolean | undefined; })[]—
onFinish *() => void—
classNamestring—

TeamGrid

component
PropTypeDefault
people *readonly Person[]—
classNamestring—

JobBoard

component
PropTypeDefault
jobs *readonly Job[]—
onApply *(job: Job) => void—
classNamestring—

Accessibility #

It exposes status, alert, img and group semantics, with aria-label, aria-hidden, aria-invalid, aria-current, aria-labelledby and aria-pressed kept in step with state. Changes that matter are announced through a live region.

No custom key handling; Tab and the native activation keys do the work.

Motion #

It declares no animation in its component source. Any transition comes from its stylesheet, which uses the duration tokens that collapse to instant under prefers-reduced-motion.