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.
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.AppSidebar.tsx:395-433).mutedChannelIdsis already available inAppShell, so this is a natural filter rather than a new data path.shared/lib/keyboard-shortcuts.tsunderNavigation, so it appears in Settings → Keyboard Shortcuts automatically.Windows uses
Ctrl+Alt+arrowsrather than Slack's plainAlt+arrowsbecauseAlt+←/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.mjsunit test (matching the convention infeatures/sidebar/lib/), add auseChannelNavigationShortcutshook alongside the existinguseMarkAsReadShortcuts, and add an e2e case tonavigation.spec.ts.Known limitation in this first pass
Sidebar collapse state (
collapsedGroups/collapsedSections) is localReact.useStateinsideAppSidebarand 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 intoAppShell. 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.