feat(ui): dialog close confirmation - #9439
Open
maxyinger wants to merge 2 commits into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 4e4cf8a The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
9 tasks
maxyinger
force-pushed
the
max/dialog-close-confirmation
branch
from
August 13, 2026 17:35
df92efe to
a848c54
Compare
maxyinger
added a commit
that referenced
this pull request
Aug 13, 2026
Let an explicit `handle.open(payload)` win over the stale `activeTriggerId` lookup, keep the payload published through the exit transition so a `handle.close()` no longer blanks children-as-function content, and settle an in-flight question `false` when `<AlertDialog.Confirm>` unmounts rather than poisoning the handle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
maxyinger
force-pushed
the
max/dialog-close-confirmation
branch
from
August 13, 2026 19:59
a848c54 to
01220eb
Compare
Contributor
API Changes Report
Summary
No API Changes DetectedAll packages have stable APIs with no detected changes. Report generated by Break Check Last ran on |
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/electron
@clerk/electron-passkeys
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-google-signin
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
maxyinger
added a commit
that referenced
this pull request
Aug 13, 2026
Let an explicit `handle.open(payload)` win over the stale `activeTriggerId` lookup, keep the payload published through the exit transition so a `handle.close()` no longer blanks children-as-function content, and settle an in-flight question `false` when `<AlertDialog.Confirm>` unmounts rather than poisoning the handle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
maxyinger
force-pushed
the
max/dialog-close-confirmation
branch
from
August 13, 2026 22:24
01220eb to
4027545
Compare
9 tasks
maxyinger
force-pushed
the
max/dialog-close-confirmation
branch
from
August 13, 2026 23:08
4027545 to
248ec82
Compare
maxyinger
force-pushed
the
max/dialog-close-confirmation
branch
from
August 14, 2026 15:01
248ec82 to
e08c483
Compare
A dialog holding unsaved work should ask before discarding it. Three pieces,
each with one job: `createConfirmHandle()` links a question to its answer,
`useConfirmedClose` guards the close path, and `<AlertDialog.Confirm>` is the
dialog, rendered inside the one it guards so the two share a floating tree —
escape ordering, the stacking styles and the refcounted scroll lock all read
that tree, and a globally mounted confirmation would break every one of them.
`show()` returns a promise resolving to the answer, so a confirmation reads as
`if (await confirm.show({…}))` rather than as a pair of state variables and a
callback. Calling it while one is already showing returns the IN-FLIGHT promise
instead of opening a second: holding Escape against a guarded dialog would
otherwise stack a confirmation per keypress.
The veto is the absence of a commit. `useConfirmedClose` wraps the consumer's
own `onOpenChange`, so it covers every close the dialog owns — Escape, outside
press, `Dialog.CloseButton`, `Dialog.Close`, and the `close` the wrapper hands
its children all funnel through it. A button wired to the consumer's own
`setOpen(false)` never reaches the dialog and so bypasses the question; that is
inherent, and both the hook's JSDoc and the docs page say so.
Two ordering details that are load-bearing. The action settles `true` before
closing, and `settle` is a no-op once a question is answered, so the close that
follows cannot overwrite the answer with `false`. And the hook reads `when` and
`onOpenChange` through a ref, so the callback identity is stable across the
keystrokes of the very form whose dirtiness `when` reports on.
Headless gains `handle.open(payload)` — the programmatic counterpart of a
trigger's payload, which is how the confirmation's own text reaches it. The
root holds it in a ref as well as in state: the registry lookup that runs once
the dialog is open resolves a trigger-less open to `undefined`, and would
otherwise blank the dialog a commit after it was filled.
Let an explicit `handle.open(payload)` win over the stale `activeTriggerId` lookup, keep the payload published through the exit transition so a `handle.close()` no longer blanks children-as-function content, and settle an in-flight question `false` when `<AlertDialog.Confirm>` unmounts rather than poisoning the handle. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
maxyinger
force-pushed
the
max/dialog-close-confirmation
branch
from
August 14, 2026 20:40
e08c483 to
4e4cf8a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
https://swingset-git-max-dialog-close-confirmation.clerkstage.dev/components/alert-dialog ->
Confirm a discardDescription
createConfirmHandle()— promise-based, so a confirmation reads asif (await confirm.show({…}))<AlertDialog.Confirm>— rendered inside the dialog it guards, not app-globaluseConfirmedClose()— wraps the dialog's ownonOpenChangeDialog.CloseButton,Dialog.Close, and thecloserender prophandle.open(payload)— programmatic counterpart of a trigger's payloadPreview
Swingset link tbd
Checklist
pnpm testruns as expected.pnpm buildruns as expected.Type of change