Repository navigation
Keep form buttons' height and centre their spinner while they wait - #643
Conversation
AsyncSubmitButton wrapped its spinner and word in an inline-flex span. The spinner, an empty inline-block, gave that span its baseline, so the span sat on the text's baseline with all of its height above it: the spinner rode high and buttons that aren't flex boxes grew taller while waiting (Save on Settings went from 36 to 39px). A block-level flex box centres the contents and keeps the button's height. justify-center keeps them centred in buttons wider than their text. A new e2e spec holds the server action open and measures Save and "Yes, delete signup" on the Settings tab at 1280 and 390px. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ac17ipj2bhcShNz3whFhDc
Tophat: passedRan 265de49 locally with
Not clicked: the OAuth consent screen's full-width buttons. The PR's run of For the owner (UX): while a form button waits (Save, Yes, delete signup, Create signup, Remove, Disconnect), it no longer grows 1–3px taller and then snaps back, and its spinner sits in the middle instead of slightly high. At rest, every button looks exactly as it did. Buttons in the signup header and the phone's More actions sheet don't change. Screenshots: Screenshots are in https://claude.ai/code/session_01WTzR5GhEz2dQbgzgZTCJhi. Generated by Claude Code |
Keeps both Unreleased › Fixed CHANGELOG lines (#586 from main, #636 here). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01R9pje6Yt5WfLsBarh5RpiK
richshaw
left a comment
There was a problem hiding this comment.
Review: passed (round 1)
This PR turns the wrapper inside AsyncSubmitButton from inline-flex items-center into flex items-center justify-center, as the issue outlined. The wrapper no longer gets its baseline from the empty spinner, so a waiting button keeps its height and its spinner sits in the middle. I checked every caller (Settings Save and "Yes, delete signup", "Yes, remove" on Responses, Create signup, Close signup in the ⋯ panel and the phone sheet, Disconnect, and Allow / Don't allow). None of their buttons is a flex box or uses text-left, so their contents were already centred by the button's default text-align: center. justify-center therefore keeps the resting look the same, including on the full-width consent and phone-sheet buttons. The new e2e spec measures height and spinner position at both widths, and the PR says it failed before the fix.
Blocking (0): none
Optional (1):
CHANGELOG.md:77: the entry lists "Publish" among the buttons this fixes, butPublishButtondoesn't useAsyncSubmitButton. Its "Checking…" already sits in a block-level grid, as the issue says. Dropping "Publish and" would make the line accurate, but it isn't worth a round of its own.
Earlier threads: none (Copilot couldn't review: quota used up)
Checks: CI green on d9308bd (lint-type-test, e2e, CodeQL). The only commit since the passing tophat (265de49) is a merge from main; the shared runtime-change check prints 0. No local runs were needed: there were no findings to prove.
Why the owner: UX. Every waiting form button changes slightly: it no longer grows 1–3px or lifts its spinner. Look at the tophat's before/after screenshots (643-before/after-desktop-save, -phone-delete, -desktop-create) and the unchanged header Publish and phone-sheet Close.
https://claude.ai/code/session_01XikuxTBxb75uCEbycXLzmj
Generated by Claude Code
|
Approved by the owner at Session: https://claude.ai/code/session_01MTLHRSYbwK1vKjngmLNWUb Generated by Claude Code |
|
Not merged: the branch is behind Session: https://claude.ai/code/session_016yEFqND3Wf8TSeER8F44Ny Generated by Claude Code |
…c-button-centre # Conflicts: # CHANGELOG.md
|
Merged Ran on the merge and all passed: Session: https://claude.ai/code/session_016yEFqND3Wf8TSeER8F44Ny Generated by Claude Code |
|
Approved by the owner at Session: https://claude.ai/code/session_01DFKGuYh28iFmKJaws6mXzT Generated by Claude Code |
Through the server, telemetry and screen branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UW9ZpEu4MWkeqTv2Qe14ks
Fixes #636.
The problem
While a form button waits for its answer, it shows a spinner and a word like "Saving…". In
AsyncSubmitButtonthey sat in aninline-flexspan whose first item, the spinner, is an emptyinline-block, so the span took its baseline from the spinner's bottom edge. The span then sat on the text's baseline with all 16px above it: the spinner rode high, and buttons that aren't flex boxes themselves grew taller while waiting. Save on a signup's Settings tab went from 36px to 39px, then snapped back.The fix
src/components/ui/async-submit-button.tsx: the wrapper is nowflex items-center justify-center gap-2instead ofinline-flex items-center gap-2, as the issue outlined.justify-centerkeeps the contents centred in buttons wider than their text, such as the consent screen's full-width ones.justify-centerdoes nothing, and the sheet's buttons stay left-aligned.Tests
tests/e2e/async-submit-button.spec.ts: at 1280px and 390px it holds the Settings tab's server actions open, then checks that Save ("Saving…") and "Yes, delete signup" ("Deleting…") keep their height and that the spinner's middle is within 0.5px of the button's.pnpm lint && pnpm typecheck && pnpm knip && pnpm test(1,389 tests),pnpm build && pnpm budgets, and the new spec plusresponses,organizerandoauth-consentagainst the production build (22 passed).affected-articles.mjsnames three help pages that show these buttons. Their wording, steps and resting appearance are the same, so none needed editing.Session: https://claude.ai/code/session_01Ac17ipj2bhcShNz3whFhDc
Generated by Claude Code