Repository navigation
fix(domains): the Remove Domain tooltip opens, so a disabled Remove says why - #1863
Merged
dawsontoth merged 0 commit intoOct 12, 2026
Conversation
Contributor
There was a problem hiding this comment.
Code Review
This pull request wraps the "Remove Domain" button in a div container inside the TooltipTrigger to ensure the tooltip is displayed even when the button is disabled, and adds corresponding unit tests. The review feedback suggests improving accessibility for keyboard and screen-reader users by adding a conditional tabIndex to the wrapper div when the button is disabled.
dawsontoth
added this pull request to stack #1912
October 11, 2026 22:28
Coverage Report
File CoverageNo changed files found. |
dawsontoth
marked this pull request as ready for review
October 12, 2026 17:07
dawsontoth
force-pushed
the
claude/1843-domain-remove-tooltip
branch
from
October 12, 2026 17:07
f07861f to
d56bf21
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.
⊙ Problem
On a cluster's Domains page, the tooltip on each row's Remove Domain button never opened. A bound domain's Remove is disabled, and nothing said why; an unbound domain never showed its DNS-cleanup reminder (#1843). The trigger slotted onto a fragment, which can take neither Radix's props nor its ref, so React dropped every handler and logged
Invalid prop … supplied to React.Fragmenton each render: 100 times in oneManagement.test.tsxrun.Stack:
stage← #1801 ← #1802 ← #1840 ← #1846 ← this PR. It is based on #1846's branch (claude/1686-domain-change-preflight) because that stack is rewriting this table. Retarget it once the stack lands.💡 Solution
The tooltip now triggers on the Remove control itself, and which element that is depends on whether the button can take focus. An enabled Remove is its own trigger, so hover and keyboard focus both open the DNS reminder, and Radix's
aria-describedbylands on the element that has focus. A bound domain's Remove is disabled, and a disabled button takes no pointer events or focus, so atabIndex={0}wrapper stands in as the trigger (the comment that says so). Mouse and keyboard users now get "To delete this domain, please unbind it from all clusters first." on a bound row, and "Remember to clean up your DNS records!" on an unbound one. TheReact.Fragmentwarning is gone from the test run.The wrapper is keyed on the domain being bound, not on the button being disabled. While any domain change is in flight every Remove is disabled, and keying on that would give each unbound row a tab stop whose tip doesn't explain why.
🔧 Changes
src/features/cluster/domains/constants/tableDefinition.tsx: the Remove button is built once and handed toTooltipTrigger asChildeither bare or inside the bound-row wrapper. The domain name moves out of the tooltip and stays above it, so the layout is unchanged.💬 gemini-code-assist feedback
The bot asked for a conditional
tabIndexon the wrapper so keyboard users can reach a disabled Remove's tooltip. Fixed in f258657 as suggested, then reworked in f07861f after the pre-push round below found two problems with it: the description sat on the wrapper while an enabled button held focus, and keying onisPendingadded tab stops during any change.✅ Verification
End-to-end route: component test through the real Radix tooltip, not a browser. Port 5173 is shared by parallel sessions here. Radix opens a tooltip from its trigger's
onPointerMoveandonFocus, and setsaria-describedbyon that trigger while open (@radix-ui/react-tooltip/dist/index.mjs:186,:190,:208), and the repo'sTooltipProviderdefaultsdelayDurationto 0, so the test exercises the same handlers a mouse and a keyboard do. What a screen reader announces is not tested beyond thearia-describedbylink.src/features/cluster/domains/Management.test.tsx, newthe Remove Domain tooltipblock, which finds the trigger by thedata-stateRadix puts on it and importsactto move focus:aria-describedbyagainst the tooltip's id;npx vitest run src/features/cluster/domains/Management.test.tsx --silent=false: 53 passed, exit 0, 0React.Fragmentwarnings. On the base branch it was 45 passed with 100 such warnings.aria-describedbywas null) and the pending test; dropping the wrapper'stabIndexfails the disabled-focus test; keying the wrapper onisPendingfails the pending test. At 58d0420, restoring the fragment trigger failed both hover cases, and putting the name back inside the trigger failed both.npx tsc -b,npx oxlint --format stylish .,npx dprint checkall exit 0.git fetch, and the Harper domain adjudicator failed both on an expired Claude OAuth session. Adopted then: narrowing the trigger to the button. A third round at f258657 ran codex, gemini and the Harper domain adjudicator. Adopted: describing an enabled Remove on the button, and not keying the wrapper onisPending(both in f07861f). Dropped by the adjudicator on evidence: "a 20ms wait can't prove the tooltip stayed closed", since everyTooltipmounts a provider withdelayDuration0 (src/components/ui/tooltip.tsx:9,:25). Kept: the one source comment, now cut to the constraint, because it is what stops someone from moving the trigger back onto a disabled button.🤖 Generated by Anthropic Claude Code (Claude Opus 5.5); posted via @dawsontoth.
🤖 Generated with Claude Code
Related PRs: #1846 overlaps (this PR's base; it edits the same table definition and test file), 3 others independent
Complexity: easy
Review-Coverage: authored=claude; ran=gemini,codex; adjudicated=domain; blocked=cursor-composer(no-receipt),cursor-muse(no-receipt); declined=cursor-grok,cursor-kimi; rounds=3; full=1 @ f07861f
Review-Attention: read ~3m (decisions: wrapper-always-vs-only-when-disabled, focusable-wrapper-vs-aria-disabled, pending-state-tab-stop) @ f07861f