Active sessions
The places an account is signed in, as a list with a dot map. Signing out other sessions sends a wave from this device that removes them nearest first.
Your data
Pass your sessions as sessions (or defaultSessions) and sign them out in onRevoke. Without them the component shows six invented demo sessions. See Your data.
Playground
Change a prop and the component re-renders. Props marked remounts set an initial value, so the component starts over.
<GeoSessions confirm title="Active sessions" />
Installation
pnpm dlx shadcn@latest add @lumesec/geo-sessionsFirst timeRegister the @lumesec registry once, or install by URL+
Adds @lumesec to your components.json:
pnpm dlx shadcn@latest registry add @lumesec=https://elements.lumesec.ai/r/{name}.jsonOr skip the setup and install by URL:
npx shadcn@latest add https://elements.lumesec.ai/r/geo-sessions.jsonUsage
import { GeoSessions, type Session } from "@/components/lumesec/geo-sessions";
export function Example({ sessions, revoke }: { sessions: Session[]; revoke: (ids: readonly string[]) => void }) {
return <GeoSessions defaultSessions={sessions} onRevoke={revoke} />;
}Behaviour
The places an account is signed in, as a list with a compact map above it. Each row shows the device type, the city and when it was last active; pointing at a row pulses its point and draws a line from this device to it.
Sign out other sessions sends a wave across the map from this device. As it reaches each session, the point breaks up into sparks and its row collapses at the same moment, nearest first.
API reference
Props
Also accepts every prop of <div> (React.ComponentProps<"div">), spread onto the root element.
sessionsTypereadonly Session[]Sessions (controlled): { id, device, label, city, lat?, lon?, lastActive, current?, approximate? }. device is laptop, desktop, phone, tablet or terminal; lastActive is epoch ms, an ISO date-time or a Date. Use with onSessionsChange. An empty array shows "No active sessions".
defaultSessionsTypereadonly Session[]Default6 demo sessionsSessions when uncontrolled. Without sessions and defaultSessions the component shows six invented sessions.
onSessionsChangeType(sessions: readonly Session[]) => voidCalled with the remaining sessions after a sign-out, once the rows have collapsed.
onRevokeType(ids: readonly string[]) => voidCalled with the ids that were signed out, at the same moment as onSessionsChange. Not called for the demo sessions.
confirmTypebooleanDefaulttrueRequires a second click within 4 seconds to sign out all other sessions. A single row's Sign out never asks.
nowTypenumberReference time in epoch ms for the relative times. Gives the same text on the server and the client. Without it a clock starts after mount and refreshes every 30 seconds.
localeTypestringDefault"en-US"BCP 47 locale of the relative times and dates.
titleTypeReact.ReactNodeDefault"Active sessions"Header text.
Ref
ref points at the root HTMLDivElement.
Keyboard
| Keys | Action |
|---|---|
| Tab | Moves through the rows' Sign out buttons and the footer button. A focused row previews its session on the map. |
| ArrowDown / ArrowUp | Moves focus to the next or previous row's Sign out button. |
| Home / End | Moves focus to the first or last row's Sign out button. |
| Enter / Space | On a row: signs out that session. On the footer: arms it, and a second press within 4 seconds signs out all other sessions. |
| Escape | Disarms the footer button. |
Accessibility
- The sessions are a list labelled "Sessions". Each row is text (label, city, relative time) and a native button whose accessible name names the session, such as "Sign out Office desktop, Berlin".
- The armed footer button's accessible name follows the rolled label ("Confirm sign-out"), and it is described by "Press again within 4 seconds to confirm".
- With no other sessions left, the footer button reads "No other sessions" and is
aria-disabled, so it keeps focus after a sign-out. - After a sign-out, focus moves to the next row's button, or to the footer button.
- A polite live region announces the result, such as "5 sessions signed out".
- Collapsing rows are
inertand hidden from assistive technology. The map and its canvases arearia-hidden; the list carries the same data. - Reduced motion: there is no wave, implode or sparks and no first reveal of the land: rows are removed at once, the count and the labels change without rolling, the preview line appears without drawing on and the point does not pulse. The confirm fuse still burns down, without flicker.
Theming
Styled with Tailwind classes on your shadcn theme tokens, so light and dark follow your theme. The accent comes from --lumesec. See Theming.
This component reads --lumesec, --lumesec-glint, --lumesec-shine, --destructive, --card, --card-foreground, --muted, --muted-foreground, --foreground and --border.
Notes
- The map is an Equal Earth strip cropped to 50° S to 72° N, drawn from the embedded world data with no map tiles. A session outside that band sits on the nearest edge. Sessions without
latandlonhave no point; during a sweep they go after the front has crossed the map. - Sign out other sessions starts a front at this device (the session with
current), or at the middle of the map when there is none. It travels at 420 px per second; each session's row collapses on the frame the front reaches its point, and sessions at the same place go together. - Before mount, rows with your data show absolute dates in UTC, such as "Oct 3, 14:20 UTC". Pass
nowfor relative times in the server markup. - With controlled
sessions, signed-out rows stay hidden until you pass a new array. Keep the old array while your request runs; a new array that still contains a session brings its row back.
Related
Was this page helpful?