Skip to content

feat(lint): ban native title tooltips and migrate to styled Tooltip - #7209

Merged
juliusmarminge merged 12 commits into
pingdotgg:mainfrom
UtkarshUsername:feat/oxlint-no-native-title-tooltip
Aug 16, 2026
Merged

feat(lint): ban native title tooltips and migrate to styled Tooltip#7209
juliusmarminge merged 12 commits into
pingdotgg:mainfrom
UtkarshUsername:feat/oxlint-no-native-title-tooltip

Conversation

@UtkarshUsername

@UtkarshUsername UtkarshUsername commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

What Changed

  • Added a lint rule. A new t3code/no-native-title-tooltip oxlint rule bans the native title attribute as a tooltip. It only fires on lowercase intrinsic elements (span, button, p, ...), so it ignores title used for accessibility (iframe, SVG <title>) and title passed as a custom component prop.
  • Migrated the existing tooltips. Every native title tooltip in the web app (33 flagged by the rule, plus a few on pass-through components it can't see) now uses the styled Tooltip / TooltipTrigger / TooltipPopup. Redundant ones (where the visible label already said it) just had the title removed.

Migrated Tooltips:

Sidebar / global chrome

  • Sidebar.tsx - "Discard draft" (X button on draft rows)
  • Sidebar.tsx - "Dismiss Woke notification" (amber pill button)
  • Sidebar.tsx - "Dismiss Woke notification" (top status pill button)
  • ConnectionStatusDot.tsx - connection status text (dot button, tooltip was pre-existing; I only removed the duplicate native title)
  • ChatView.tsx - scroll-to-end button: native title removed (redundant with visible label); no tooltip now

Settings

  • ConnectionsSettings.tsx - pairing-link expiry line (e.g. "Expires in 2h")
  • ConnectionsSettings.tsx - QR pairing URL <code> (truncated, full URL on hover)
  • ConnectionsSettings.tsx - endpoint HTTP base URL <p>
  • ConnectionsSettings.tsx - pending Tailscale MagicDNS endpoint (tooltip only when set)
  • ProjectSettingsPanel.tsx - "Copy path" (copy checkout path button)
  • ThemeColorPicker.tsx - "Choose {label} color" (color swatch)
  • ThemeColorPicker.tsx - "{Show/Hide} where {label} is used" (usage toggle button)

Pull requests

  • PullRequestChecksPopover.tsx - check description (or name) on truncated check name
  • PullRequestSummaryTab.tsx - 2× file-path tooltips (comment.path)
  • pullRequestPresentation.tsx - actor login (avatar + login row)
  • PullRequestCodeTab.tsx - commit message headline; orphan-file path
  • PullRequestDetailPanel.tsx - repo name; open-PR-number button (2 variants: expanded/condensed); PR title; branch range "base ← head"; base branch <code>; "Copy pull request branch" / "Copied" (copy-branch button)
  • PullRequestDetailPanel.tsx auto-merge Badge: "The host will merge this on its own once its requirements are met"
  • PullRequestListFilters.tsx host disabled reason + project disabled reason tooltips

Chat / composer

  • DraftHeroHeadline.tsx - active project name (the dotted heading; tooltip only when a project is resolved)
  • DraftHeroHeadline.tsx - group display name in project picker menu items
  • ChangedFilesTree.tsx - file path on preview-file button
  • ComposerPreviewAnnotationCards.tsx - "1 region / N regions", "1 style change / N style changes" counters

Preview / files

  • ThreadPreviewMiniPlayer.tsx - "Open in right panel"
  • ThreadPreviewMiniPlayer.tsx - "Pop into separate window" / "Close separate window"
  • ThreadPreviewMiniPlayer.tsx - "Close floating preview"
  • FilePreviewPanel.tsx - breadcrumb crumb full path

Diff

  • DiffPanel.tsx - branch comparison "head → base" on the compare row
  • DiffPanel.tsx - "Remote only" (remote-branch checkmark)
    Host picker / search
  • _chat.pull-requests.tsx - host disabled reason (e.g. why a host is unavailable) on menu items
  • ProjectContentSearchDialog.tsx - {label} on search option toggle buttons
    Browser device toolbar
  • BrowserDeviceToolbar.tsx - "Lock aspect ratio" / "Unlock aspect ratio"

Why

AI models keep using the native tooltip instead of the app's styled tooltip component. This has regressed a few times. Native title tooltips don't match the app's look and can't be styled. The rule is scope-tight so it catches real native tooltips without false-positiving on accessibility uses or component props, and it's wired in as an error so future regressions fail CI.

UI Changes

image image image image image image image image image image image image

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Broad but mechanical UI-only changes with no auth, data, or API behavior; main risk is minor tooltip/hover regressions on disabled controls or truncated text.

Overview
Adds t3code/no-native-title-tooltip as an oxlint error so intrinsic JSX elements cannot use title for hover hints (with carve-outs for accessibility names like iframe and for custom components). Existing web UI title tooltips are replaced with Tooltip / TooltipTrigger / TooltipPopup across sidebar, chat, diff, PR views, settings, search, file preview, and browser toolbar.

Disabled menu items that used title for “unavailable” reasons now wrap the item in a tooltip and use data-disabled:pointer-events-auto so hover still works. PullRequestActorLabel gains an optional tooltip={false} to avoid double tooltips where callers wrap avatars themselves. A few redundant native titles are dropped (e.g. scroll-to-end label); the mini-player resize handle keeps aria-label only.

Reviewed by Cursor Bugbot for commit 774d434. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Ban native title tooltips across the web app and migrate to styled Tooltip components

  • Adds a new t3code/no-native-title-tooltip oxlint rule (no-native-title-tooltip.ts) that errors on title attributes used as tooltips on intrinsic JSX elements, registered in vite.config.ts.
  • Migrates all existing native title tooltip usages across pull request, chat, sidebar, settings, search, file preview, and browser toolbar components to use Tooltip + TooltipTrigger + TooltipPopup.
  • Disabled menu items that previously used title to show unavailability reasons now apply data-disabled:pointer-events-auto so custom tooltips can still trigger.
  • Behavioral Change: Browser-native title tooltips are replaced with styled popups app-wide; tooltip timing, appearance, and positioning will now follow the app's Tooltip component behavior rather than the browser's native behavior.

Macroscope summarized 774d434.

Add t3code/no-native-title-tooltip, an oxlint rule that reports title attributes on intrinsic HTML elements and directs authors to the styled Tooltip component. The pin button regression in pingdotgg#6371 happened partly because nothing enforced the preference, so warn now and flip to error once existing usages are migrated.
@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 851d22f8-7814-4843-8442-16520b3b6ec3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Aug 16, 2026
Comment thread apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the titleTooltip migration for consistency with the shared tooltip primitive. Most conversions match the existing Tooltip / TooltipTrigger render={…} / TooltipPopup idiom and preserve aria-labels and layout (the Tooltip root emits no DOM, so flex parents are unaffected).

Four call sites changed interaction ownership rather than just the tooltip mechanism: three now put the trigger around an interactive child that owns its own hover surface (tooltip positioner is z-[140], popover/combobox popups are z-[130]), and one attaches the trigger to an element the design system explicitly makes non-hoverable.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx Outdated
Comment thread apps/web/src/components/DiffPanel.tsx Outdated
Comment thread apps/web/src/routes/_chat.pull-requests.tsx Outdated
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the titleTooltip migration for consistency with the shared tooltip primitive. Most conversions match the existing Tooltip / TooltipTrigger render={…} / TooltipPopup idiom and preserve aria-labels and layout (the Tooltip root emits no DOM, so flex parents are unaffected).

Four call sites changed interaction ownership rather than just the tooltip mechanism: three now put the trigger around an interactive child that owns its own hover surface (tooltip positioner is z-[140], popover/combobox popups are z-[130]), and one attaches the trigger to an element the design system explicitly makes non-hoverable.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/routes/_chat.pull-requests.tsx Outdated
Comment thread apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx Outdated
Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated
Comment thread apps/web/src/components/DiffPanel.tsx Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 9c2f68d. Configure here.

Comment thread apps/web/src/routes/_chat.pull-requests.tsx Outdated
@macroscopeapp

macroscopeapp Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 774d434

Mechanical migration replacing native title attributes with an existing styled Tooltip component across UI files, plus a new lint rule to enforce the pattern. No behavior changes beyond tooltip styling consistency.

You can customize Macroscope's approvability policy. Learn more.

Comment thread apps/web/src/components/settings/ConnectionsSettings.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UI Consistency

The four issues flagged on the previous head are addressed (DiffPanel trigger now scopes to the head-ref text, the PR header tooltip no longer swallows PullRequestBaseFreshnessWarning, the pairing-expiry trigger no longer wraps AccessScopeSummary, and the compact filter menu anchors on a hoverable wrapper instead of the disabled MenuRadioItem).

One new finding, inline: the "Remote only" indicator in DiffPanel.tsx loses its accessible name in the migration (the title was the only text, and the icon is aria-hidden).

Also worth noting (no inline comment possible — the lines are outside the diff): the new t3code/no-native-title-tooltip rule only matches lowercase intrinsic elements, so title props that shared primitives forward straight to the DOM still render native tooltips. Two remain next to the surfaces this PR migrated: PullRequestDetailPanel.tsx:1414 (<Badge title="The host will merge this on its own…">, which useRender spreads onto a span, in the same header row that was converted) and PullRequestListFilters.tsx:166,383 (<MenuRadioItem title={option.unavailable}> — the twin of the CompactFilterMenu case converted in _chat.pull-requests.tsx). Converting those keeps hover behavior uniform; otherwise the rule silently leaves the pattern it was added to eliminate.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/DiffPanel.tsx Outdated

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One consistency finding on the disabled-menu-item tooltip in _chat.pull-requests.tsx. The rest of the migration matches the existing tooltip contract (Tooltip > TooltipTrigger render={...} > TooltipPopup), keeps aria-labels, and the earlier hover-surface overlaps (DiffPanel combobox, PullRequestBaseFreshnessWarning, AccessScopeSummary) are resolved.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/routes/_chat.pull-requests.tsx Outdated
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 16, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review August 16, 2026 15:44

Dismissing prior approval to re-evaluate 620d91d

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 16, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review August 16, 2026 16:03

Dismissing prior approval to re-evaluate 2805cc9

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Aug 16, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: the base-freshness warning changed position in the PR detail toolbar as a side effect of the tooltip migration. Everything else in this pass looks consistent with the existing tooltip contracts (disabled menu items now use the data-disabled:pointer-events-auto pattern from RightPanelTabs, icon-only triggers keep an accessible name, and hover popovers are no longer nested inside tooltip triggers).

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/pullRequest/PullRequestDetailPanel.tsx
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 16, 2026

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: PullRequestActorLabel now owns a tooltip, which stacks a second popup on the reviewer avatar stack that already wraps it in its own tooltip trigger. Everything else in this migration (disabled menu items re-enabling pointer events per the RightPanelTabs contract, render={<Button/>}/render={<PopoverTrigger/>} composition, preserved aria-labels, scoped triggers next to the freshness popover and the base-ref combobox) matches existing conventions, and no wrapped control sits under a [data-slot="button"]/[data-slot="toggle"] themed container or a Group, so the trigger's data-slot takeover has no styling fallout here.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/pullRequest/pullRequestPresentation.tsx

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One finding: PullRequestActorLabel now owns a tooltip, which stacks a second popup on the reviewer avatar stack that already wraps it in its own tooltip trigger. Everything else in this migration (disabled menu items re-enabling pointer events per the RightPanelTabs contract, render={<Button/>}/render={<PopoverTrigger/>} composition, preserved aria-labels, scoped triggers next to the freshness popover and the base-ref combobox) matches existing conventions, and no wrapped control sits under a [data-slot="button"]/[data-slot="toggle"] themed container or a Group, so the trigger's data-slot takeover has no styling fallout here.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/pullRequest/pullRequestPresentation.tsx
@macroscopeapp
macroscopeapp Bot dismissed their stale review August 16, 2026 17:03

Dismissing prior approval to re-evaluate 4b89f77

@macroscopeapp macroscopeapp Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the tooltip migration against the shared Tooltip contract and the affected call sites. The earlier findings (double trigger on the reviewer avatars, the reordered base-freshness warning, the combobox/popover hover collisions, the unreachable disabled-menu-item reasons, and the unlabeled remote-only icon) are all addressed in this revision, and the disabled-item pattern now matches the RightPanelTabs precedent (data-disabled:pointer-events-auto + trigger rendered onto the item).

One remaining item: the mini-player resize handle now carries hover chrome.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/preview/ThreadPreviewMiniPlayer.tsx Outdated
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 16, 2026
@macroscopeapp
macroscopeapp Bot dismissed their stale review August 16, 2026 17:21

Dismissing prior approval to re-evaluate 774d434

@juliusmarminge
juliusmarminge merged commit fee10de into pingdotgg:main Aug 16, 2026
18 of 19 checks passed
@UtkarshUsername
UtkarshUsername deleted the feat/oxlint-no-native-title-tooltip branch August 16, 2026 19:44
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Aug 16, 2026
juliusmarminge added a commit that referenced this pull request Aug 17, 2026
Re-applies the deltas that mid-stack blob reverts discarded, and merges
main's round-9 work into the v2-owned surfaces:

- settings: main's Integrations page (#7082) coexists with the branch's
  Scheduled Tasks page in the path union, section labels, icons, and
  search catalog
- contracts: main's preview appearance/zoom/viewport settings imports
  restored beside the branch's modelSelection home for ModelSelection
- mobile: main's built-in themes (#6619) re-applied to the v2 thread
  screens and work log (useThemeColor over hand-rolled color-scheme
  ternaries)
- MessagesTimeline: main's #7157 cleanup adopted (toolCallExpandedBody
  class name unexported, implementation-detail test dropped)
- ChangedFilesTree: main's styled tooltip (#7209) carrying the v2 runId
- pullRequestDetail tests: branch's row-action coverage renamed onto
  main's buildAddSelectionToAgentHandoff (#6597)
- lint: migrated the six branch-owned native title tooltips that main's
  new no-native-title-tooltip rule (#7209) flags to styled Tooltips
  (GitActionsControl, QueuedRunsControl, TimelineSystemDivider,
  MessagesTimeline intent badge and MCP tool logo)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
sandscooling pushed a commit to sandscooling/t3code that referenced this pull request Aug 17, 2026
Upstream pingdotgg#7209 added t3code(no-native-title-tooltip), which is an error-level
rule banning the native title attribute on intrinsic elements. The composer
activity row was the only carried change still using one.

The row keeps its hover hint, now as a Tooltip popup, and gains an aria-label
that the native attribute was previously supplying.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
radroid added a commit to radroid/t3code that referenced this pull request Aug 17, 2026
Upstream added the `no-native-title-tooltip` oxlint rule in fee10de (pingdotgg#7209) and
migrated its own call sites in the same commit. The fork's UpdateToast.tsx was not
in that sweep -- it is fork-owned -- so the new rule turned the fork's lint red on
a file upstream has never seen.

Migrated to the same Tooltip/TooltipTrigger/TooltipPopup idiom upstream used, so
the build-provenance affordance keeps its explanation and lint goes green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
0x00-sys added a commit to 0x00-sys/t3code that referenced this pull request Aug 17, 2026
Upstream pingdotgg#7209 banned native `title` tooltips and migrated call sites to the
styled Tooltip, which collided with this branch's consistency pass on nine
files. Each conflict is resolved by taking upstream's Tooltip structure and
re-applying the consistency fix that had been on the replaced element:

- Sidebar, ChangedFilesTree, DraftHeroHeadline, PullRequestDetailPanel,
  ProjectSettingsPanel, ThemeColorPicker: keep upstream's Tooltip wrapper,
  restore `cursor-pointer` / `transition-colors` / focus ring-offset.
- ThreadPreviewMiniPlayer: upstream dropped the redundant `title`; the
  focus-visible ring this branch added is kept.
- GitActionsControl: take upstream's `min-w-0` (replaces `truncate` so
  StartTruncatedPath can truncate itself) plus this branch's `cursor-pointer`.
- scroll-area: keep the shared SCROLL_FADE_SIZE_CLASS constant and fold in
  upstream's new `scroll-p-[var(--fade-size)]`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
radroid added a commit to radroid/t3code that referenced this pull request Aug 18, 2026
Upstream added the `no-native-title-tooltip` oxlint rule in fee10de (pingdotgg#7209) and
migrated its own call sites in the same commit. The fork's UpdateToast.tsx was not
in that sweep -- it is fork-owned -- so the new rule turned the fork's lint red on
a file upstream has never seen.

Migrated to the same Tooltip/TooltipTrigger/TooltipPopup idiom upstream used, so
the build-provenance affordance keeps its explanation and lint goes green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants