Session timeout
FreeA fair warning before a session ends: a dialog counts down with a ring, offers to stay signed in, and signs out at zero.
pnpm dlx shadcn@latest add https://caliperui.site/r/session-timeout.jsonSigned in.
When to use #
Use it for
- Banking, health and admin tools with short sessions.
- Shared computers.
Skip it when
- Consumer apps that keep people signed in.
Installation #
pnpm dlx shadcn@latest add https://caliperui.site/r/session-timeout.json
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.
Usage #
This is the code behind the preview above.
import { useState } from "react" import { Button } from "@/components/ui/button" import { SessionTimeout } from "@/components/ui/session-timeout" const wait = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)); export function SessionTimeoutDemo() { const [expiresAt, setExpiresAt] = useState<number | null>(null); const [note, setNote] = useState("Signed in."); return ( <div className="grid justify-items-center gap-3"> <Button variant="secondary" onClick={() => { setNote("Session ends in 20 seconds."); setExpiresAt(Date.now() + 20_000); }}>End my session in 20 seconds</Button> <p className="text-xs text-muted-foreground" role="status">{note}</p> {expiresAt && ( <SessionTimeout expiresAt={expiresAt} warnBefore={15} onExtend={async () => { await wait(500); setExpiresAt(null); setNote("You are still signed in."); }} onSignOut={() => { setExpiresAt(null); setNote("Signed out."); }} /> )} </div> ); }
API reference #
SessionTimeout
component
Accessibility #
It exposes alertdialog semantics, with aria-hidden and aria-live kept in step with state. Changes that matter are announced through a live region.
Keyboard and focus handling comes from Radix dialog: arrow keys move through items, Enter and Space select, and Escape closes and returns focus.
Motion #
Transitions use the shared duration and easing tokens. Under prefers-reduced-motion those tokens collapse to instant and travel distances go to zero, so state changes still happen without movement.