Six ready-made modals on the Dialog primitive: type-to-confirm delete, create project, success with a self-drawing check, keyboard shortcuts, upgrade to Pro and invite teammates with email chips.
Confirm delete
confirm-delete.tsxAlert dialog that lists what will be lost and arms the destructive button only once the project name is typed exactly.
| Prop | Type | Default | Description |
|---|---|---|---|
projectName* | string | — | Text the user must type to enable Delete. |
onConfirm | () => void | Promise<unknown> | — | Runs on confirm; a promise shows a pending state and the modal closes when it resolves. |
consequences | { icon?: ReactNode; text: string }[] | — | What will be lost, one line each. |
trigger | ReactElement | — | Element that opens the modal; it receives onClick, aria-haspopup and aria-expanded. |
open / defaultOpen / onOpenChange | boolean / boolean / (open: boolean) => void | — | Controlled or uncontrolled open state. |
Create project
create-project.tsxForm modal with a live URL preview under the name, visibility as native radio cards and a native template select.
| Prop | Type | Default | Description |
|---|---|---|---|
workspace | string | "acme" | Handle shown in the URL preview. |
templates | { value: string; label: string }[] | — | Options for the Start from select. |
onCreate | (project: { name; slug; visibility; template }) => void | Promise<unknown> | — | Runs on submit; a promise shows a pending state. |
trigger | ReactElement | — | Element that opens the modal; it receives onClick, aria-haspopup and aria-expanded. |
open / defaultOpen / onOpenChange | boolean / boolean / (open: boolean) => void | — | Controlled or uncontrolled open state. |
Success
success.tsxCentred celebration: the check draws itself as a ring ripples out, then next steps blur in one by one.
| Prop | Type | Default | Description |
|---|---|---|---|
title / description | string / ReactNode | — | Confirmation copy. |
steps | { icon?; title; description?; onClick? }[] | — | Next steps; with onClick they become buttons. |
primaryLabel / onPrimary | string / () => void | "Open site" | Primary action; the modal closes after it runs. |
trigger | ReactElement | — | Element that opens the modal; it receives onClick, aria-haspopup and aria-expanded. |
open / defaultOpen / onOpenChange | boolean / boolean / (open: boolean) => void | — | Controlled or uncontrolled open state. |
Keyboard shortcuts
keyboard-shortcuts.tsxWide sheet of grouped shortcuts with keycaps and a filter box; groups reflow with layout springs and it opens on “?” too.
| Prop | Type | Default | Description |
|---|---|---|---|
groups | { title: string; shortcuts: { label: string; keys: string[] }[] }[] | — | Shortcut groups shown in two columns. |
listenForQuestionMark | boolean | true | Open when ? is pressed outside a text field. |
trigger | ReactElement | — | Element that opens the modal; it receives onClick, aria-haspopup and aria-expanded. |
open / defaultOpen / onOpenChange | boolean / boolean / (open: boolean) => void | — | Controlled or uncontrolled open state. |
Upgrade to Pro
upgrade-to-pro.tsxEmber-accented upsell with a monthly / yearly switch on a gliding pill, a price that blurs between cycles and a feature list.
| Prop | Type | Default | Description |
|---|---|---|---|
prices | { monthly: number; yearly: number } | { monthly: 15, yearly: 12 } | Price per seat per month for each cycle. |
currency | string | "$" | Currency symbol. |
features | string[] | — | What Pro includes. |
defaultCycle | "monthly" | "yearly" | "yearly" | Initially selected billing cycle. |
onUpgrade | (cycle) => void | Promise<unknown> | — | Runs on upgrade; a promise shows a pending state. |
trigger | ReactElement | — | Element that opens the modal; it receives onClick, aria-haspopup and aria-expanded. |
open / defaultOpen / onOpenChange | boolean / boolean / (open: boolean) => void | — | Controlled or uncontrolled open state. |
Invite teammates
invite-teammates.tsxEmail chip field (Enter, comma, space or paste a list; Backspace removes) that flags bad addresses, a role select and a copy-link action.
| Prop | Type | Default | Description |
|---|---|---|---|
workspace | string | "Acme" | Shown in the title. |
inviteLink | string | — | Copied by Copy invite link. |
max | number | 20 | Max addresses per batch. |
onInvite | ({ emails, role }) => void | Promise<unknown> | — | Runs with valid addresses; a promise shows a pending state. |
trigger | ReactElement | — | Element that opens the modal; it receives onClick, aria-haspopup and aria-expanded. |
open / defaultOpen / onOpenChange | boolean / boolean / (open: boolean) => void | — | Controlled or uncontrolled open state. |
Install the whole set
Installs every modal recipes variant at once. Each section above has its own command for a single variant.
Pro installs use your private registry token. Add the @geturui-pro registry once — setup guide. The command works after you get Pro.
Accessibility
- Built on Dialog: focus trap, focus restore, Escape and scrim dismissal, labelled title and description, bottom sheet below 640px.
- Forms use real labels, native radios and selects, aria-invalid with worded errors, and submit buttons linked to their form.
- Pending actions show a busy button and block dismissal; live regions announce results, copy states and filter counts.