Mantle Dialog.Footer DOM Order Migration Guide
@ngrok/mantle's Dialog.Footer no longer reverses its children. Previously it
applied flex-row-reverse, which laid its children out right-to-left, so
the DOM order was the visual mirror of what you wrote. It now uses normal
flex with justify-end, so children render left-to-right in DOM order,
matching Sheet.Footer and AlertDialog.Footer.
TL;DR: For every Dialog.Footer with two or more children, reverse the
order of its direct children. The conventional layout is the secondary/cancel
action first and the primary action last (so the primary action stays on the
right). Footers with a single child need no change.
Codemod
From a mantle checkout:
In a project that installs @ngrok/mantle:
The rules apply step 2 to a Dialog.Footer with exactly two actions: they swap the two in place, and nothing else in the footer moves. A comment-only expression such as {/* note */} is not an action, so it neither counts nor moves. A footer with three or more actions stays manual, because a rule cannot reverse a list of any length. A mapped list counts as one action, so reverse its array by hand. A footer with its own text beside the two actions stays manual, because the swap moves the two actions only. The rules read a part through its import from @ngrok/mantle/dialog, under its own name or an alias. A part that reaches the file through a local re-export or a destructured namespace stays manual. A function that binds Dialog to a parameter or a local shadows the import, so the rules leave that function alone. Run the codemod once: a swapped footer is still a two-child footer, so a second run swaps it back. Pass --dry-run to print the rewrites first, and run your formatter after the rewrite.
You are an agent migrating a codebase. Do this:
- Find every
Dialog.Footer(the footer of@ngrok/mantle'sDialogcompound component). Search forDialog.Footer, and for any destructured or renamed imports of the same component (e.g.const { Footer } = Dialog;orimport { Footer } from "@ngrok/mantle/dialog"). - For each
Dialog.Footerwith two or more direct children, reverse the order of those direct children. Do not touch the children's internals, only their order. - Leave
Dialog.Footerinstances with zero or one direct child unchanged. - Do not touch
Sheet.FooterorAlertDialog.Footer. They already render in DOM order and are not affected by this change. - After editing, re-run the project's formatter, linter, and type checker.
Why reverse? The visual result must stay the same. Under the old
flex-row-reverse, the first DOM child rendered on the right. Code was therefore written primary-action-first to put the primary action on the right. Now that children render in DOM order, primary-action-first would put the primary action on the left. Reversing restores the intended left-to-right appearance (secondary/cancel on the left, primary on the right).
Before → after
Two actions (most common)
Destructive confirmation
Single action: no change
Edge cases & gotchas
- More than two children. The rule is the same: reverse the full child
order. A footer rendered
[A, B, C]under the old reversal appeared as[C, B, A]; to preserve that appearance, write[C, B, A]now. - Conditional children. When children are rendered with
&&, ternaries, or.map, reverse the order in which they appear, not just the static JSX. For mapped lists, reverse the array (or render order) so the visual sequence is unchanged. - Custom
classNameonDialog.Footer. If a footer overrode the layout (e.g. added its ownflex-row-reverse,flex-row, orjustify-*), review it by hand: the base class change may interact with the override. The base now contributesflex justify-end. Dialog.Footerwith non-action content (text, links, a left-aligned hint alongside buttons): verify the layout visually. If it relied on the reversal for positioning, adjust with explicit classes rather than DOM order.- Single-child footers and footers you cannot confidently reorder: leave them and flag them for human review rather than guessing.
How to verify
- Open each affected dialog and confirm the buttons appear in the same visual order as before the change (typically secondary/cancel on the left, primary on the right).
- Confirm tab order now follows visual order left-to-right. (This is a secondary benefit of the change: under the old reversal, keyboard tab order did not match visual order.)
- Run the project's formatter, linter, type checker, and tests.