Skip to content

feat(desktop): keyboard shortcut to navigate to next/previous channel #3078

Description

@eddieberklee

Problem

There's no way to move between channels from the keyboard. Every channel switch requires the mouse or a round-trip through quick search (⌘K) — typing a name you already know to reach a channel that's already visible in the sidebar. Slack, Discord, and IRC clients all have a single-chord next/previous-conversation binding, and its absence is felt immediately when working across a few adjacent channels.

Proposal

Add ⌥↓ / ⌥↑ (Ctrl+Alt+↓ / Ctrl+Alt+↑ on Windows) to move the active channel selection down/up the sidebar list.

  • Order matches what the sidebar displays: starred → custom sections in section order → unassigned, each honoring its own sort preference (as assembled in AppSidebar.tsx:395-433).
  • Scope: the active community's stream channels. Forums and DMs are out of scope here.
  • Muted channels are skipped. mutedChannelIds is already available in AppShell, so this is a natural filter rather than a new data path.
  • Stops at both ends rather than wrapping — no wraparound surprise when you're walking to the top or bottom of a list deliberately.
  • No-op when the list is empty or no channel is selected (e.g. on the home feed).
  • Registered in shared/lib/keyboard-shortcuts.ts under Navigation, so it appears in Settings → Keyboard Shortcuts automatically.

Windows uses Ctrl+Alt+arrows rather than Slack's plain Alt+arrows because Alt+←/Alt+→ are already bound to back/forward there (useBackForwardControls.ts:92-106).

Implementation sketch

The displayed-order flattening currently lives inline in AppSidebar.tsx. I'd extract it into a shared helper so the shortcut and the sidebar can't drift apart, cover it with a .test.mjs unit test (matching the convention in features/sidebar/lib/), add a useChannelNavigationShortcuts hook alongside the existing useMarkAsReadShortcuts, and add an e2e case to navigation.spec.ts.

Known limitation in this first pass

Sidebar collapse state (collapsedGroups / collapsedSections) is local React.useState inside AppSidebar and isn't reachable from an app-level shortcut hook. So navigating into a collapsed group will switch the channel correctly but leave the group shut, meaning the selection highlight isn't visible until you expand it. Making the shortcut collapse-aware — expand on arrival, or skip collapsed groups — requires lifting that state into AppShell. Happy to do that here or as a follow-up, but it restructures state ownership, so I'd rather you called the shape.

Also happy to follow up with

⌥⇧↓ / ⌥⇧↑ for next/previous unread, which is where Slack's mute-skipping behavior properly belongs. Keeping this PR to the plain case.

Checking the keybinding and scope look right before I open the PR.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions