Rime

TypeToConfirmModal and DangerZone

The heaviest confirm: an impact preview and a typed phrase; and the Danger zone section that leads to it.

TypeToConfirmModal shows what will change (ImpactPreview), asks for a typed phrase (copyable, case-insensitive by default) and runs an async onConfirm, showing an error in place if it fails.

DangerZone is the section at the foot of a settings or record page that holds destructive actions, one DangerZoneRow each, each opening its confirm.

Installation

npx shadcn@latest add KezLahd/rime/danger-zone

Also installs: base, button, type-to-confirm.

Usage

import { DangerZone, DangerZoneRow, TypeToConfirmModal } from "@/components/ui";

<DangerZone>
  <DangerZoneRow title="Remove team member" actionLabel="Remove team member" confirm={{ title: "Remove Jane Cooper?", phrase: "remove jane cooper", confirmLabel: "Remove team member", onConfirm: remove, impact: ITEMS }} />
</DangerZone>

Examples

Open

The confirm itself, rendered in place with inline.

Danger zone

Danger zone

Actions here can't be undone.

  • Remove team member

    Signs them out everywhere and revokes their access.

API

Generated from the component's TypeScript types and JSDoc (scripts/gen-ui-registry.mjs), so it always matches the source.

TypeToConfirmModal

TypeToConfirmModal props
PropTypeDefaultDescription
openRequiredboolean
onCloseRequired() => voidCancel, Esc, scrim, the close button, and a confirm that went through.
titleRequiredReactNode
metaReactNodeA quiet line under the title: the record's name or reference.
descriptionReactNode
inlinebooleanRender the open dialog in place (see Modal's inline).
impactImpactItem[] | ImpactPreviewPropsWhat the action does, one row per consequence, in the impact panel above the phrase. Pass the rows, or the full ImpactPreview props for a preview that loads from the server (loading, error, onRetry).
consequencesReactNodeProse consequences. Still supported: shown as plain text inside the impact panel, above any rows. Prefer `impact` for new dialogs.
consequencesTitleReactNode"This action cannot be undone"The compact danger line heading the impact panel.
phraseRequiredstringWhat the user types to arm the button. Keep it specific to the thing being destroyed ("delete atlas redesign"), so muscle memory can't confirm the wrong record. Shown verbatim; lower-case reads best.
caseSensitivebooleanfalseDefault false: "Jane Cooper" matches "jane cooper".
childrenReactNodeExtra required fields (a training date). Rendered between the impact panel and the phrase.
canConfirmbooleantrueValidity of the children. The button arms only when this and the phrase both hold.
confirmLabelRequiredstring
cancelLabelstring"Cancel"
busyLabelstringReplaces the confirm label while onConfirm is in flight, e.g. "Deleting…".
onConfirmRequired() => void | Promise<unknown>The irreversible request. While a returned promise is pending the dialog is locked (no Esc, scrim, close or Cancel). When it resolves the dialog closes through onClose; when it rejects the dialog stays open and unlocked, the typed phrase kept, and an error toast says so.
errorTitleReactNode"That didn't go through"Title of the failure toast. The description always says nothing changed.
sizeModalProps["size"]"md"
mobileModalProps["mobile"]

DangerZone

DangerZone props
PropTypeDefaultDescription
titleReactNode"Danger zone"Default "Danger zone".
descriptionReactNodeOne line under the title: whose data this is, who can see it.
headingLevel2 | 3 | 422 on a settings page, 3 inside a titled section.
childrenReactNodeDangerZoneRow elements. The zone renders nothing without any.
classNamestring

DangerZoneRow

DangerZoneRow props
PropTypeDefaultDescription
titleRequiredReactNode
descriptionReactNodeWhat it does and what it takes with it. The button names the action; this explains it.
actionLabelRequiredstringA full verb phrase: "Deactivate team member", not "Deactivate".
confirmOmit<TypeToConfirmModalProps, "open" | "onClose">The row owns a TypeToConfirmModal with these props and opens it from the button. It closes when onConfirm resolves. For a confirm whose extra fields the page holds in state, use onAction and render the modal there.
onAction() => voidCalled instead of opening the built-in confirm.
disabledboolean
disabledReasonReactNodeShown in the row while disabled: why, and what would enable it.

Theme tokens

Per-component tokens are undeclared by default, so the default shown is the fallback the CSS uses. Set one at :root (or in theme.css) to restyle every instance. Live values are read from this page, so they follow the Rime Studio.

This component has no tokens of its own; it reads the system tokens below.

System tokens it reads

TypeToConfirmModal and DangerZone system tokens
TokenDefaultLive value
--danger-filltokens.css…
--danger-inktokens.css…
--danger-linetokens.css…
--ease-outtokens.css…
--font-bodytokens.css…
--font-monotokens.css…
--ink-bodytokens.css…
--ink-headingtokens.css…
--ink-mutedtokens.css…
--ink-secondarytokens.css…
--linetokens.css…
--line-softtokens.css…
--r-xltokens.css…
--shadow-inputtokens.css…
--success-filltokens.css…
--success-inktokens.css…
--success-solidtokens.css…
--surface-solidtokens.css…
--text-bodytokens.css…
--text-captiontokens.css…
--text-card-titletokens.css…
--text-smalltokens.css…
--wash-activetokens.css…

Accessibility

  • The confirm button stays disabled until the phrase matches; progress toward the phrase is announced through a polite status region.

Do and don't

Do

  • Make the phrase name the thing being destroyed.

Don't

  • Don't use it for everyday deletes; ConfirmModal is enough.

For AI agents

This page as markdown, rendered from the same registry entry. Point an agent at it (or add .md to this page's URL), or at /llms.txt for the index.

Open type-to-confirm.md