Skip to content

vscode: standardize the toggle pattern across the extension — swap vs VS Code's single-button toggled menu #969

@amrmelsayed

Description

@amrmelsayed

Exploratory issue — surfaced from the #952 plan-approval discussion. The plan-approval gate for the current feature picks one pattern for its own use; this issue's job is the broader question — should the whole extension converge on one toggle pattern?

Problem — two patterns coexist by accident

The VSCode extension has accumulated several view-state toggles, each currently implemented as a two-command swap: two distinct commands with two distinct icons, the when-clause on each entry chooses which is visible based on current state. The icon shows the target action (what clicking will do), not the current state.

Known instances of this pattern today (post-#952 shipping):

Toggle Commands Icons (off → on target) Setting backing it
Backlog mine vs all codev.showBacklogMineOnly / codev.showBacklogAll $(eye) / $(eye-closed) codev.backlogShowAll
Builders file view list vs tree codev.enableBuildersFileTreeMode / codev.disableBuildersFileTreeMode $(list-tree) / $(list-flat) codev.buildersFileViewAsTree
Builders group-by area vs phase (landing in #952) codev.setBuildersGroupByArea / codev.setBuildersGroupByPhase $(tag) / $(milestone) codev.buildersGroupBy

(There may be others — first task in any plan here is an audit.)

The alternative is VS Code's built-in toggled menu property: one fixed button at a fixed position, one fixed icon, with a pressed / highlighted visual state that reflects the current setting. Click flips the setting; the button's appearance updates to show "this is active." Native VSCode views use this pattern heavily (Source Control's "View as Tree/List", Outline's filter toggles, etc.).

The tradeoff (the design call)

Two-command swap (current pattern):

  • ✅ Per-state icons — visually distinct icon for each side of the toggle, so the user sees what they'll get if they click
  • ✅ Matches the convention already in use in this extension (familiarity for current users)
  • ✅ Fits cases where the two states have intrinsically different semantics (e.g. mine vs all isn't "more / less" — it's two different filters)
  • ❌ Two commands per toggle to maintain (titles, when-clauses, palette entries can drift)
  • ❌ Button visually "moves" between two icons depending on state — a glance doesn't tell you which mode you're in without recognising both icons

Single-button toggled (the alternative):

  • ✅ One command per toggle, simpler config
  • ✅ Native VSCode pattern — engineers using other extensions / VSCode itself will recognise it
  • ✅ The button position is fixed, which reduces "where did that go?" moments after a toggle
  • ✅ Current state is visually obvious (pressed / unpressed)
  • ❌ Only one icon — can't visually distinguish what the other state would look like
  • ❌ Some toggles' two states aren't naturally "on / off" (mine-vs-all again — toggled-mine = "filtered to me" is a fine read, but toggled-all = "showing everything" is the off state which is semantically the more permissive mode, mildly confusing)

Questions the plan-gate should answer

  1. Audit first. What's the full list of toggles in packages/vscode/? Three are known; an honest count may reveal more (status-bar toggles, dev-server start/stop is not one, but accordion-mode might be).
  2. One pattern, or mixed? Is the goal to converge to a single pattern across all toggles, OR is the answer "use swap when states are semantically distinct (mine vs all), use toggled when states are naturally on/off (auto-collapse enabled)"? A mixed answer is defensible but needs criteria, not just case-by-case.
  3. Which toggles, if any, are bad fits for the chosen pattern? Some toggles may be intrinsically swap-shaped (the per-state icon carries information the user needs); the conversion should respect that.
  4. Migration cost. Converting an existing toggle changes which setting key writes happen, which palette entries appear, and how custom keybindings resolve. Are any existing keybindings widely-bound in a way that the change would break user muscle memory?
  5. Discoverability tradeoff. Native toggled pattern is more discoverable for VSCode-native users; swap pattern is more discoverable in the abstract (you can see both states' icons in the title bar... no wait, you can only see one at a time). The discoverability argument may favour toggled.

What this isn't

Acceptance (loose pending plan-gate)

  • An audit identifies all existing toggle controls in the extension.
  • A decision is recorded for each: stays as swap / converts to toggled / explicitly defers.
  • If any convert: the conversion is implemented behaviour-preservingly (same setting key, same default, same backing config — only the UI surface changes).
  • The chosen pattern is documented in codev/resources/arch.md (or a similar durable location) so future toggle additions follow it without re-litigating.

Related

  • #952 — the Builders group-by toggle that surfaced this question; ships as a swap to match today's convention.

Metadata

Metadata

Assignees

Labels

area/vscodeArea: VS Code extensionprojectNew project or feature

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions