Community Wolf
Community
APIAboutContact
Book a demo

Community Wolf

Real-time safety intelligence for citizens and the teams who protect them.

Community Tools

  • Public map
  • Namola
  • WhatsApp

Business Tools

  • Access Control
  • Intelligence
  • Safety API
  • Group Agents
  • Patrol Management
  • Roster Management
  • Safety Survey
  • Pricing
  • Pricing calculator

Resources

  • Docs
  • Changelog
  • Design system

Company

  • Community
  • Business
  • API
  • About
  • Contact

Get pilot updates

New features, city launches, and integration partnerships - delivered monthly.

Subscribe to updates

(c) 2026 Community Wolf. All rights reserved.

Privacy PolicyTerms of Service
Wolf design system
Foundations
  • Brand
  • Voice and tone
  • Colour
  • Typography
  • Spacing and layout
  • Radius, elevation and borders
  • Motion
  • Iconography
  • Imagery and photography
  • Data visualisation
  • Accessibility
Patterns
  • App shell
  • Hero sections
  • Empty states
  • Error states
  • Skeletons and loading
  • Forms
  • Tables and data density
  • Confirmation and destructive actions
  • Authentication surfaces
Components
  • Button
  • Input
  • Card
  • Badge
  • Dialog
  • Label
  • Textarea
  • Select
  • Checkbox
  • Radio group
  • Switch
  • Form field
  • Tabs
  • Popover
  • Tooltip
  • Accordion
  • Alert dialog
  • Confirm dialog
  • Toast (Sonner)
  • Skeleton
  • Empty state

patterns

Confirmation and destructive actions

Friction proportional to consequence. Titles are questions, descriptions state what's affected, buttons use verbs — never 'Yes' or 'OK.'

Read the full spec

Live specimen — destructive confirm

Trigger opens the shared ConfirmDialog with the destructive variant. Initial focus lands on Cancel; Escape cancels.

tsx
import { ConfirmDialog } from "@wolf/design-system";

const [open, setOpen] = useState(false);

<Button variant="destructive" onClick={() => setOpen(true)}>
  <Trash2 /> Delete report
</Button>

<ConfirmDialog
  open={open}
  onOpenChange={setOpen}
  title="Delete this report?"
  description="The report will be removed from the feed, along with 3 attached notes. This can't be undone."
  confirmLabel="Delete report"
  destructive
  onConfirm={async () => { await deleteReport(id); }}
/>

Non-destructive confirm — add friction, not alarm

Use the default variant when the action needs a second thought but isn't irreversible.

When to confirm

Friction proportional to consequence. Delete a report? Yes. Mark as read? No.

  • Always confirm

    • — Deleting a report, area, user or patrol
    • — Removing a guard from a group
    • — Sending a mass alert (>10 recipients)
    • — Cancelling a subscription
    • — Bulk actions affecting more than 10 items
  • Don't confirm

    • — Saving a draft or a setting
    • — Marking a report as read
    • — Toggling a preference
    • — Filtering or sorting a list
    • — Single low-stakes reversible actions

Copy rules

Question title, plain description, verb in the confirm button — never 'Yes' or 'OK.'

  • Avoid

    Are you sure you want to delete this?

    Good

    Delete this report?

  • Avoid

    This action cannot be undone.

    Good

    This can't be undone.

  • Avoid

    Please confirm.

    Good

    [Cancel] [Delete report]

  • Avoid

    Yes / No · OK / Cancel

    Good

    Cancel / Delete report · Keep subscription / Cancel subscription

Keyboard and a11y

ConfirmDialog uses role=alertdialog. Cancel has initial focus; Escape cancels; backdrop click does not dismiss destructive dialogs.

  • EnterActivates the confirming button
  • EscapeCancels and closes the dialog
  • Initial focusLands on Cancel — prevents accidental destruction
  • Backdrop clickDismisses non-destructive only; destructive requires explicit click
Previous — PatternsTables and data density
Next — PatternsAuthentication surfaces