Problem / motivation
This issue is filed from a production Cratis consumer. The complete evidence, costs, options and explicit non-goals follow.
Status: OPEN — filed 2026-08-07. Kind: missing seam. Package: @cratis/components (Dialog) + @cratis/arc.react (CommandDialog).
The row lives in ../CRATIS_UPSTREAM_IMPROVEMENTS.md.
The seam Cratis should provide
Dialog's okCancelFooter renders its OK button with autoFocus: true, and CommandDialog defaults buttons = DialogButtons.OkCancel. There is no prop to say "this dialog is destructive — do not arm its primary button on open."
The only escape is replacing the footer with a custom buttons ReactNode — and that is not a workaround, because it also:
- flips
closable to false,
- makes
onHide a no-op,
- severs
CommandDialog's handleConfirm, so the command never executes.
The ask: an initialFocus / autoFocusPrimary prop on Dialog, honoured by CommandDialog. Which button should take focus, and which dialogs count as destructive, stay the consumer's policy — the seam is only that the choice be expressible without discarding the footer's behaviour.
Where Ada paid the cost
Source/Core/Compliance/Retention/Confirm/ConfirmDialog.tsx — the dialog that authorises irreversible destruction of a person's personal data, and under D82 the only path by which it happens.
An independent review found a one-keystroke destruction path: the row trigger and the dialog's OK carried the same label, a native <button> fires click on keydown, and autoFocus put the mounted dialog's OK under the same held key. Auto-repeat, or the ordinary habit of pressing Enter twice, collapsed a two-step confirmation into one act.
⚠️ The asymmetry is what makes this a seam rather than an Ada mistake. Ada's reversible action — Postpone — was protected for free, because its mandatory comment leaves the OK gated by isCommandFormValid. The irreversible one was not, precisely because it needs no input. The framework protects the dialog that asks for something and arms the one that asks for nothing, which is exactly backwards for a destructive action.
Ada closed it by adding an acknowledgement checkbox purely to create a shut gate. That is a real cost, not a wash: it is a control the user must operate that exists for no domain reason, on a compliance surface where every extra step is friction an advisor will learn to click through — and it is one more thing between an advisor and a deletion they have already decided to make.
The seam vs. Ada's taste
The seam: a dialog should be able to say where initial focus goes without forfeiting closable, onHide and the command execution path.
Ada's taste, which Cratis need not adopt: Ada would additionally like destructive dialogs to require an explicit acknowledgement. That is Ada's policy and Ada can build it — as it now has. The upstream ask is only that the focus choice not be bundled with three unrelated behaviours.
Problem / motivation
This issue is filed from a production Cratis consumer. The complete evidence, costs, options and explicit non-goals follow.
The seam Cratis should provide
Dialog'sokCancelFooterrenders its OK button withautoFocus: true, andCommandDialogdefaultsbuttons = DialogButtons.OkCancel. There is no prop to say "this dialog is destructive — do not arm its primary button on open."The only escape is replacing the footer with a custom
buttonsReactNode — and that is not a workaround, because it also:closabletofalse,onHidea no-op,CommandDialog'shandleConfirm, so the command never executes.The ask: an
initialFocus/autoFocusPrimaryprop onDialog, honoured byCommandDialog. Which button should take focus, and which dialogs count as destructive, stay the consumer's policy — the seam is only that the choice be expressible without discarding the footer's behaviour.Where Ada paid the cost
Source/Core/Compliance/Retention/Confirm/ConfirmDialog.tsx— the dialog that authorises irreversible destruction of a person's personal data, and under D82 the only path by which it happens.An independent review found a one-keystroke destruction path: the row trigger and the dialog's OK carried the same label, a native
<button>firesclickon keydown, andautoFocusput the mounted dialog's OK under the same held key. Auto-repeat, or the ordinary habit of pressing Enter twice, collapsed a two-step confirmation into one act.Postpone— was protected for free, because its mandatory comment leaves the OK gated byisCommandFormValid. The irreversible one was not, precisely because it needs no input. The framework protects the dialog that asks for something and arms the one that asks for nothing, which is exactly backwards for a destructive action.Ada closed it by adding an acknowledgement checkbox purely to create a shut gate. That is a real cost, not a wash: it is a control the user must operate that exists for no domain reason, on a compliance surface where every extra step is friction an advisor will learn to click through — and it is one more thing between an advisor and a deletion they have already decided to make.
The seam vs. Ada's taste
The seam: a dialog should be able to say where initial focus goes without forfeiting
closable,onHideand the command execution path.Ada's taste, which Cratis need not adopt: Ada would additionally like destructive dialogs to require an explicit acknowledgement. That is Ada's policy and Ada can build it — as it now has. The upstream ask is only that the focus choice not be bundled with three unrelated behaviours.