FSAI Design System
Patterns

Confirmation Modals

Pattern for confirming destructive or high-risk actions before they execute.

Overview

Critical actions in the platform should usually require explicit confirmation before they run.

This pattern exists to prevent accidents for actions that are:

  • destructive
  • difficult to undo
  • bulk-affecting
  • externally visible
  • high-risk enough that an accidental click would be costly

In the platform, confirmation is generally implemented with a modal rather than a browser confirm dialog or a lightweight inline prompt.

When Confirmation Fits

Good fit:

  • deleting content, entities, or relationships
  • changing a setting that resets or removes important configuration
  • cancelling, revoking, or expiring something important
  • actions that notify external users or affect multiple records
  • bulk actions with meaningful consequences

Usually not needed:

  • reversible low-risk toggles
  • standard save actions
  • navigation
  • harmless UI preferences

Over-confirming everything creates friction, so use this pattern deliberately.

Overlay rule:

  • a confirmation modal must not open on top of another modal
  • a panel must not open on top of a modal just to continue a confirmation flow

If the user is already in a modal, keep the confirmation inside that same modal flow or reconsider whether the first surface should have been a panel instead.

Choose The Right Abstraction

Use thisWhen it fits
ConfirmActionModalThe feature already owns modal state, or the flow needs custom close behavior or extra modal content
ConfirmActionButtonA single button should open confirmation inline in a form, footer, or panel action area
Menu.ItemWithConfirmationThe action originates from a Menu or Panel.Menu and should confirm before executing
ModalThe flow is not really a simple confirmation and needs a richer custom dialog or multi-step interaction

Raw Confirmation Modal

Use raw ConfirmActionModal when state is already feature-owned:

<ConfirmActionModal
  isOpen={isConfirmOpen}
  handleClose={() => setIsConfirmOpen(false)}
  onConfirm={handleDeleteCollection}
  title="Delete Collection"
  description={`Are you sure you want to delete "${collection.name}"? This will remove the collection but keep the assets.`}
  buttonLabel="Yes, delete"
  isPending={isDeleting}
/>

This is common when the confirmation must coordinate with local screen state or multiple possible follow-up actions.

Inline Confirmation Button

Use ConfirmActionButton when the trigger and confirmation belong together:

<ConfirmActionButton
  title={`Delete "${event.subject}"?`}
  description="This event will be deleted permanently and removed from all calendars."
  variant="destructive"
  onConfirm={handleDeleteEvent}
  isPending={isDeletingEvent}
>
  Delete Event
</ConfirmActionButton>

This keeps the triggering action and the confirmation flow in one place.

Use Menu.ItemWithConfirmation when the action starts in a menu:

<Panel.Menu.ItemWithConfirmation
  label="Delete Location"
  icon="TrashCan02"
  variant="destructive"
  onSelect={handleDeleteLocation}
  confirmTitle="Delete location?"
  confirmDescription="This action cannot be undone."
  confirmButtonText="Delete"
/>

Prefer this over manually opening a sibling modal unless the flow genuinely needs special handling.

Copy Guidelines

Confirmation copy should make the consequence obvious:

  • title should name the action clearly
  • description should say what will happen and whether it can be undone
  • confirm button text should match the action, such as Delete, Remove Access, or Change Event

Avoid vague copy like Are you sure? with no context.

Also avoid delete-focused default copy when the action is not deletion.

Async And Error Handling

ConfirmActionModal awaits onConfirm.

That means:

  • success closes the modal
  • thrown errors keep the modal open
  • onSuccess only runs after a successful confirm

If the flow can fail, make sure the feature surfaces the error clearly and manages pending state intentionally.

Brand Dashboard Usage Patterns

Representative usages:

PatternPathNotes
Configuration reset confirmationfsai/apps/brand-dashboard/src/pages/Workflows/components/config-panel/TriggerConfig.tsxGood example of a destructive action that is not deletion.
Panel menu destructive actionfsai/apps/brand-dashboard/src/modules/locations/components/LocationPanel/LocationPanel.tsxUses Panel.Menu.ItemWithConfirmation for destructive entity actions.
Actions menu abstractionfsai/apps/brand-dashboard/src/components/ActionsMenu/ActionsMenu.tsxAutomatically routes items with showsConfirmationModal into Menu.ItemWithConfirmation.
Inline form actionfsai/apps/brand-dashboard/src/pages/Home/Calendar/CalendarEventInformation/CalendarEventForm.tsxConfirmActionButton inside a form action row.
Manual menu + confirm modalfsai/apps/brand-dashboard/src/modules/library/components/CollectionDropdown.tsxShows the fallback pattern when menu-driven confirmation needs local modal state.
Content deletionfsai/apps/brand-dashboard/src/pages/Learning/components/CoursesTab.tsxStraightforward controlled confirmation modal.

Relationship To Other Docs

  • See the ConfirmActionModal component page for the exact API.
  • See the Menu component page for menu-specific confirmation item details.
  • See the Modal component page for richer dialogs that go beyond a simple confirmation step.

Guidelines

  • Do confirm destructive or high-risk actions with a modal
  • Do use Menu.ItemWithConfirmation when the action originates from a menu
  • Do make the consequence explicit in the title, description, and confirm button label
  • Do reserve generic Modal for cases that are more complex than a simple yes/no confirmation
  • Don't add confirmation friction to low-risk reversible actions
  • Don't stack a confirmation modal on top of another modal
  • Don't rely on delete-focused default copy for unrelated actions

On this page