Skip to content

feat: two-finger trackpad swipes go back and forward - #26991

Closed
ipanasenko wants to merge 2 commits into
pingdotgg:mainfrom
ipanasenko:feat/trackpad-swipe-navigation
Closed

ipanasenko wants to merge 2 commits into
pingdotgg:mainfrom
ipanasenko:feat/trackpad-swipe-navigation

Conversation

@ipanasenko

@ipanasenko ipanasenko commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Hey guys!
I haven't tested this on Linux/Windows - feel free to take over this PR or just close.
But I use this gesture all the time and I really miss it in T3 Code 🙏

Note

🤖 Written by Claude Opus 5.5 on behalf of Illia

Problem

On a Mac trackpad, Chrome and Safari go back and forward with a two-finger horizontal swipe. T3 Code had no such gesture: Electron doesn't implement it in the desktop app, and the web build turned the browser's own gesture off with overscroll-behavior: none on html, body. History navigation was only reachable through mod+[ and mod+].

Change

Web: overscroll-behavior: none becomes overscroll-behavior-y: none, so the browser's native swipe-back works again. Vertical overscroll stays off, which is what #2392 added the rule for.

Desktop (macOS): a new SwipeNavigation overlay in AppSidebarLayout draws a Chrome-style arrow and calls the same window.history.back() / forward() as navigation.back / navigation.forward.

wheel (passive listener on window)
  advanceSwipeGesture        dead zone, then axis and direction lock
    canStartSwipe            history can go that way, no dialog, no scroller that still scrolls that way
  paint (rAF)                arrow slides in from the edge, page fades; half circle = armed
  release
    scroll end (desktopBridge.onTrackpadScrollEnd)    navigate if armed
    momentum seen (swipeGestureCoasting)              navigate if armed
    blur, hidden, route change, modified wheel        cancel, ignore the rest of the scroll
  • Neither Blink nor Electron reports finger lift: Blink drops phase-ended wheel events before the DOM, and Electron's input-event carries only the event type. Chromium's gestureScrollEnd, already bridged for the device viewer, arrives at lift, or only once macOS momentum stops, so a flick would navigate about a second late. swipeGestureCoasting recognizes momentum (six non-increasing steps of at least 6px, decaying 4% to 30%) and navigates early. The constants come from 29 traced swipes on a MacBook trackpad, including reverse-to-cancel swipes, where it never fired. Slow releases with low-speed momentum still wait for scroll end.
  • After a swipe navigates, the rest of that scroll is ignored until it ends, so momentum cannot navigate twice.
  • Follows System Settings → Trackpad → More Gestures → Swipe between pages. A new desktopBridge.getSwipeNavigationEnabled() reads AppleEnableSwipeNavigateWithScrolls, where unset means the macOS default (on). It is re-read on window focus.
  • Works over Settings and Usage (route modals). Real dialogs, the command palette and the model picker block it. A horizontal scroller that can still scroll in that direction keeps the gesture, like Chrome's scroll latching, including RTL and overscroll-behavior-x containment.
  • The arrow uses the sidebar's colors, so it follows every theme.
  • User docs: docs/user/keybindings.md mentions the swipe next to navigation.back.
  • Not included: Windows and Linux desktop (no system preference to follow, and horizontal mouse wheels look like touchpads there), and mobile, which has its own native back gestures.

Scope and approval

Proposed in discussion #18296, with no maintainer approval yet; I described this PR there. It reuses the existing history navigation and the existing trackpad scroll-end bridge.

Verification

Desktop (macOS):

Screen.Recording.2026-10-29.at.4.21.04.PM.mov
Screen.Recording.2026-10-29.at.4.22.06.PM.mov
  • apps/web/src/lib/swipeNavigation.test.ts (17 cases): dead zone and axis lock, threshold commit, reversal retracts without arming the other direction, momentum detection on traced sequences, and scroller ownership in LTR, RTL and contained cases.
  • Dev desktop app on a MacBook trackpad with seeded data: swipe back and forward, flick, hold past the threshold then release, and reverse to cancel. 29 traced swipes tuned the release detection.
  • Electron on macOS: systemPreferences.getUserDefault(key, "string") returns "" for the unset AppleEnableSwipeNavigateWithScrolls, and "1" / "0" for set booleans.
  • vp run check:changed passes.
  • Not checked: native swipe-back in Safari, Firefox and Android Chrome on the web build, and swiping over Settings and Usage by hand.

Two-way door. Blast radius: navigation. On the web, horizontal swipes outside horizontal scrollers can now trigger the browser's own back and forward. On macOS desktop, a passive window wheel listener runs a small state machine per event.

Claude Opus 5.5 in T3 Code (Claude Code harness).

ipanasenko and others added 2 commits October 29, 2026 15:30
Swiping left or right with two fingers on a Mac trackpad now moves
through history like Chrome. On the web, the browser's own gesture is
back: only vertical overscroll stays disabled. The desktop app draws a
Chrome-style arrow that follows the fingers, fades the page, and
navigates on release. It respects macOS "Swipe between pages".

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions github-actions Bot added vouch:trusted Author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 29, 2026
@ipanasenko
ipanasenko marked this pull request as ready for review October 29, 2026 15:49
@macroscopeapp

macroscopeapp Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — The change introduces default-enabled macOS trackpad history navigation and adds a line-level lint suppression. Both changes require human review under the configured requirements.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 37fbefd and 839e37a.

Files selected for processing: 11
  • apps/desktop/src/ipc/DesktopIpcHandlers.ts
  • apps/desktop/src/ipc/channels.ts
  • apps/desktop/src/ipc/methods/window.ts
  • apps/desktop/src/preload.ts
  • apps/web/src/components/AppSidebarLayout.tsx
  • apps/web/src/components/SwipeNavigation.tsx
  • apps/web/src/index.css
  • apps/web/src/lib/swipeNavigation.test.ts
  • apps/web/src/lib/swipeNavigation.ts
  • docs/user/keybindings.md
  • packages/contracts/src/ipc.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

Walkthrough

Adds macOS trackpad swipe navigation to the desktop app. The app reads the macOS swipe setting through synchronous IPC, tracks eligible gestures, and navigates browser history when a gesture commits.

Changes: Swipe Navigation

Layer / File(s) Summary
Expose the macOS swipe preference
apps/desktop/src/ipc/channels.ts, apps/desktop/src/ipc/methods/window.ts, apps/desktop/src/ipc/DesktopIpcHandlers.ts, apps/desktop/src/preload.ts, packages/contracts/src/ipc.ts
Adds a synchronous IPC channel and desktop bridge method. The method returns false outside macOS and checks the macOS swipe preference on macOS.
Track and validate swipe gestures
apps/web/src/lib/swipeNavigation.ts, apps/web/src/lib/swipeNavigation.test.ts
Adds gesture state, threshold and coasting checks, and scroll-container claim detection. Tests cover gesture transitions, coasting, and LTR/RTL scroller behavior.
Integrate gesture navigation
apps/web/src/components/SwipeNavigation.tsx, apps/web/src/components/AppSidebarLayout.tsx, apps/web/src/index.css, docs/user/keybindings.md
Mounts the navigation component in the macOS desktop app. The component tracks wheel gestures, displays progress feedback, and navigates history when a gesture commits. Updates overscroll styling and documents the trackpad behavior.

Priority: Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant AppSidebarLayout
  participant SwipeNavigation
  participant desktopBridge
  participant DesktopIpcHandlers
  participant getSwipeNavigationEnabled
  participant Trackpad
  participant BrowserHistory
  AppSidebarLayout->>SwipeNavigation: Render on macOS desktop
  SwipeNavigation->>desktopBridge: Read swipe-navigation setting
  desktopBridge->>DesktopIpcHandlers: Send synchronous preference request
  DesktopIpcHandlers->>getSwipeNavigationEnabled: Check macOS preference
  getSwipeNavigationEnabled-->>SwipeNavigation: Return enabled state
  Trackpad->>SwipeNavigation: Send wheel gesture
  SwipeNavigation->>BrowserHistory: Navigate back or forward when committed
Loading

Possibly related PRs

  • pingdotgg/t3code#25188: Adds macOS swipe handling for back and forward navigation using a different gesture mechanism.
  • pingdotgg/t3code#21723: Adds macOS swipe handling for back and forward navigation using a different gesture mechanism.

Suggested reviewers: macroscopeapp, t3dotgg

Merge Risk: Minimal · up to 839e3

This adds macOS trackpad swipe navigation that follows the system "Swipe between pages" setting. No concrete merge-blocking issue remains. Native behavior in a real macOS window was not run here, so a quick manual check is still sensible.

Pre-merge checks: Passed 3 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Description check Warning The description covers the problem, implementation, scope, and verification. However, the Scope and approval section states that the linked discussion has no maintainer approval, although the template… Obtain explicit maintainer approval for the proposed direction and scope in the linked discussion, then update the Scope and approval section with the approval comment or link.
Passed Passed checks: 3 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: two-finger trackpad swipes navigate backward and forward.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description covers the problem, implementation, scope, and verification. However, the Scope and approval section states that the linked discussion has no maintainer approval, although the template requires explicit approval for this feature.

Resolution

Obtain explicit maintainer approval for the proposed direction and scope in the linked discussion, then update the Scope and approval section with the approval comment or link.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@ipanasenko

Copy link
Copy Markdown
Contributor Author

Note

🤖 Written by Claude Opus 5.5 on behalf of Illia

Closing in favor of #9779, which a maintainer took over on Oct 19 and which uses the same two-finger horizontal swipe on desktop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted Author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant