caliper uidocs

Session timeout

Free

A fair warning before a session ends: a dialog counts down with a ring, offers to stay signed in, and signs out at zero.

Installs components/ui/session-timeout.tsxDepends on @radix-ui/react-dialog, @radix-ui/react-slot, lucide-reactMotion shared motion tokens
pnpm dlx shadcn@latest add https://caliperui.site/r/session-timeout.json

Signed 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 #

terminal
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.

example.tsx
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
PropTypeDefaultDescription
expiresAt *number—When the session ends, in milliseconds since 1970 (Date.now() style).
warnBeforenumber60Seconds before the end to show the warning.
onExtend *() => void | Promise<void>—Extends the session; may return a promise.
onSignOut *() => void—

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.