Skip to content

Browser Back does not walk back through settings tabs on desktop (tab switches replace instead of push) #951

Description

@clemenshelm

Symptom

On desktop, browser Back does not walk back through visited settings tabs. Reproduced 2026-07-28 on staging (:rc-0.9):

  1. Open Settings, click through Context → Profile → Telegram → Support.
  2. Press Back → lands on Context, not Telegram.
  3. Press Back again → leaves Settings entirely (back to the chat).

Four tab visits produced exactly one history entry.

Cause — deliberate, with an unconsidered desktop consequence

packages/web/src/hooks/use-tab-param.ts:

if (pushOnEnter && !isExplicit) {
  router.push(url, { scroll: false });
} else {
  router.replace(url, { scroll: false });
}

pushOnEnter pushes only on the transition from "no explicit ?tab=" to the first selected tab. Its doc-comment states the intent plainly: "Switching between tabs afterwards still uses replace to avoid piling up one history entry per tab click." use-tab-param.test.ts:164 pins that behaviour ("replaces (no history spam) when switching tabs while already explicit").

Traced against the report:

Action isExplicit Navigation History
Arrive at /settings false [chat, /settings]
Click Profile false push [chat, /settings, ?tab=profile]
Click Telegram true replace [chat, /settings, ?tab=telegram]
Click Support true replace [chat, /settings, ?tab=support]
Back /settings → renders Context
Back chat ✓

pushOnEnter was added for the mobile drill-down, where there is a real menu level to return to. On desktop there is no menu level — every click is a lateral switch between addressable locations, so replace means Back can never reach them.

The underlying inconsistency

The tab lives in the URL. Something that lives in the URL is a location, and users expect Back to return to a location. Writing it to the URL and then replacing it is the contradiction — it looks addressable (copyable link, works on reload) while behaving like view state.

The "history spam" concern behind the current choice is real but is the normal cost of URL-addressable tabs across the web, and the way out of Settings is the sidebar or the logo, not repeated Back presses.

Options

A — push on every user-initiated tab switch (recommended). Keep replace only for programmatic normalisation (writing the default ?tab= on load), which is what replace is for. Back then walks the tabs on desktop and still returns to the menu on mobile, since entering from the menu is itself a user-initiated switch.

Cost: leaving Settings after many clicks takes many Back presses.

B — treat the tab as pure view state, never push. Mobile then relies solely on the "‹ Settings" control, and a gesture-Back leaves Settings — which is precisely what pushOnEnter was introduced to fix. Not recommended.

Whichever is chosen, use-tab-param.test.ts:164 changes with it. Making the change without updating that test is impossible by construction, which is the right kind of friction here.

Second location, same class

packages/web/src/components/agent-settings-page-content.tsx:128 calls useTabParam("general", visibleTabs, initialTab) with no options, so pushOnEnter is false and every agent-settings tab switch replaces — including the first. Back never walks those tabs either. Whatever is decided for settings should be applied there too, or the two pages will behave differently for no reason a user can perceive.

Impact

Minor and non-blocking: no data loss, no broken state, the tabs themselves work and remain deep-linkable. It is a navigation-expectation mismatch that becomes noticeable exactly when someone explores several tabs and tries to step back.

Found during 0.9.0 Flow-4 testing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions