caliper uidocs

Slide panels

Free

Steps that move like pages: forward slides in from the right, back from the left, the height eases, and focus arrives with the new panel.

Installs components/ui/slide-panels.tsxDepends on none beyond ReactMotion none in component source
pnpm dlx shadcn@latest add https://caliperui.site/r/slide-panels.json

Your plan

Team, billed yearly: €49 per seat a month. You can change seats at any time.

When to use #

Use it for

  • Checkout, sign-up and setup wizards.
  • Any flow of a few steps in one place.

Skip it when

  • Content people compare side by side; keep it on one page.

Installation #

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

Adds its 2 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.

example.tsx
import { useState } from "react"
import { Button } from "@/components/ui/button"
import { SlidePanels } from "@/components/ui/slide-panels"

export function SlidePanelsDemo() {
  const [step, setStep] = useState(0);
  const panels = [
    { title: "Your plan", body: "Team, billed yearly: €49 per seat a month. You can change seats at any time." },
    { title: "Billing details", body: "Halden Ltd, 12 Quay Street, Dublin. VAT IE 3456789X. Invoices go to finance@halden.example, and a copy comes to you." },
    { title: "Confirm", body: "You will be charged €2,940 today for 5 seats." },
  ];
  return (
    <div className="grid w-full max-w-sm gap-3">
      <SlidePanels index={step} label="Upgrade">
        {panels.map((panel) => (
          <div key={panel.title} className="grid gap-2 rounded-[12px] p-4 shadow-[inset_0_0_0_1px_var(--border)]">
            <h3 className="text-sm font-semibold">{panel.title}</h3>
            <p className="text-sm text-muted-foreground">{panel.body}</p>
          </div>
        ))}
      </SlidePanels>
      <div className="flex justify-between gap-2">
        <Button size="sm" variant="ghost" disabled={step === 0} onClick={() => setStep((n) => n - 1)}>Back</Button>
        <Button size="sm" disabled={step === panels.length - 1} onClick={() => setStep((n) => n + 1)}>Continue</Button>
      </div>
    </div>
  );
}

API reference #

SlidePanels

component
PropTypeDefault
index *number—
label *string—
classNamestring—
children *ReactNode—

Accessibility #

It is built on native elements and keeps aria-label in step with state.

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.