What's new in 2.4
Six changes in this release. Turn the page for each one.
1A short ordered read, turned page by page: release highlights, a tour, a report. Turning a page moves it from the pile you have not read to the pile you have, so the piles show how far through you are while the counter tells you exactly.
pnpm dlx shadcn@latest add @caliper/bookletSix changes in this release. Turn the page for each one.
1Every part ships its own file. Dialog installs about 12 KB of CSS.
2Run shadcn add @caliper/<name>. No registry config needed.
3Magnetic, DrawOn, CursorLabel and AnimatedList.
4Ten parts where depth carries order, magnitude or state.
5Nothing to migrate. Edit the source you own.
6Why it is built this way, so you know what to keep when you change your copy.
pnpm dlx shadcn@latest add @caliper/booklet
Adds its 5 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.
This is the code behind the preview above.
import { Booklet } from "@/components/ui/booklet" export function BookletDemo() { const page = (title: string, text: string) => ( <> <h4 className="m-0 text-[17px] font-bold leading-tight tracking-tight">{title}</h4> <p className="m-0 text-[12.5px] leading-normal text-muted-foreground">{text}</p> <div className="mt-1 h-2 rounded bg-[linear-gradient(90deg,var(--foreground)_0_34%,var(--muted)_34%_100%)]" /> </> ); return ( <div className="w-full max-w-xl"> <Booklet label="What is new in 2.4" pages={[ page("What's new in 2.4", "Six changes in this release. Turn the page for each one."), page("Per-part stylesheets", "Every part ships its own file. Dialog installs about 12 KB of CSS."), page("Listed in shadcn", "Run shadcn add @caliper/<name>. No registry config needed."), page("Motion parts", "Magnetic, DrawOn, CursorLabel and AnimatedList."), page("Depth set", "Ten parts where depth carries order, magnitude or state."), page("Upgrading", "Nothing to migrate. Edit the source you own."), ]} /> </div> ); }
It exposes group semantics, with aria-roledescription, aria-label, aria-live and aria-hidden kept in step with state. Changes that matter are announced through a live region.
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.