Danger Zone

Keeps destructive settings visible but locked until deliberately unlocked, so a stray click doesn't delete or transfer something.

StopsStray click deleted from settings

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/danger-zone.json

The files land in your project. They're yours to edit.

Usage

danger-zone-usage.tsx
import { DangerZone, DangerZoneAction } from "@/components/ui/danger-zone"

<DangerZoneAction
  title="Transfer ownership"
  consequence="Moves acme-web to another team. You lose admin access."
  actionLabel="Transfer"
  onAction={() => setLog("Transfer started. The zone locked again.")}
/>

What it catches

  • Stray clicks on destructive actions while the section is locked
  • An unlocked section left open (idle timeout, tab hidden, focus leaving)
  • Chained destructive actions, by relocking after each one

Props

DangerZone props
PropTypeDefault
title

Heading of the section.

React.ReactNode"Danger zone"
timeout

Seconds of inactivity before it locks again. Any interaction inside restarts the count.

number60
lockAfterAction

Lock again as soon as one action has run, so one unlock can't be spent on several.

booleantrue
unlocked

Controlled lock state.

boolean—
defaultUnlocked

Initial unlocked state when uncontrolled.

booleanfalse
onUnlockedChange

Called when the section locks or unlocks.

(unlocked: boolean) => void—
unlockLabel

Text for the unlock button.

string"Unlock"
lockLabel

Text for the lock button.

string"Lock"
lockedText

Shown while locked. `{count}` is the number of actions inside.

string"{count} destructive actions are locked."
unlockedText

Shown while unlocked. `{seconds}` counts down to the auto-lock.

string"Unlocked. Locks again in {seconds}s or when you leave th…
nudgeText

Shown for a moment when a locked action is pressed.

string"Locked, so nothing happened. Unlock first if you meant it."

* required. Also accepts the native props of <section> (className, aria-*, data-*…), passed through to it.

Accessibility

  • Section labelled by its title; the unlock toggle uses aria-pressed
  • Locked actions use aria-disabled so they stay focusable and are described by their consequence
  • Escape relocks; lock state changes are aria-live="polite"
  • Actions set aria-busy while pending

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

This is a UX guard rail. Enforce on the server: Authorise every destructive action on the server and require re-authentication where it matters; the lock is a UI guard.

  • Unlocking is a deliberate click, not authentication; pair it with re-auth or typed confirmation for serious actions
  • It does not perform or confirm the action itself

What it stops

Stray click deleted from settings

Also known as

danger zone · settings page · delete account · delete project · transfer ownership · github settings · admin settings

Dependencies

Pairs well with