Skip to content

Add a bindable shortcut to collapse or expand a thread's children in the sidebar #3222

Description

@ryanbbrown

The workflow

I use parent and child threads as a work tree. When a root thread has several children, I often collapse its subtree to reduce sidebar noise, then expand it when I need to switch to a child.

With a keyboard-driven workflow, I can open visible threads and move to the previous or next thread with configurable shortcuts. I cannot collapse or expand the selected parent thread's children without moving focus to the sidebar disclosure button.

What happens today

The only control is the chevron beside a parent thread. It is a native button, so I can click it or Tab to it and press Enter or Space.

There is no app command for this action in APP_COMMAND_IDS, no row in Settings → Keyboard, and no quick-palette action. The collapse state and toggle already exist:

  • Disclosure button:
    export function SidebarChildToggleChevron({
    isCollapsed,
    expandLabel,
    collapseLabel,
    onToggle,
    revealOnHover = false,
    }: SidebarChildToggleChevronProps) {
    return (
    <button
    type="button"
    aria-expanded={!isCollapsed}
    aria-label={isCollapsed ? expandLabel : collapseLabel}
    data-sidebar-hover-actions-mobile={
    revealOnHover ? SIDEBAR_HOVER_ACTIONS_MOBILE_ALWAYS_VALUE : undefined
    }
    onClick={(event) => {
    event.preventDefault();
    event.stopPropagation();
    onToggle();
    }}
    className={cn(
    revealOnHover ? SIDEBAR_HOVER_ACTIONS_CLASS : "pointer-events-auto",
    "relative z-10 inline-flex size-5 shrink-0 cursor-pointer items-center justify-center rounded-md text-subtle-foreground outline-none ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2",
    LIST_HOVER_TRANSITION,
    )}
    >
    <Icon
    name="ChevronRight"
    className={cn(
    "size-3 transition-transform duration-150",
    !isCollapsed && "rotate-90",
    )}
    aria-hidden="true"
    />
    </button>
    );
  • Parent-thread wiring:
    {parentOptions && hasChildren ? (
    <SidebarChildToggleChevron
    isCollapsed={isParentCollapsed}
    expandLabel={`Expand ${labelTitle} threads`}
    collapseLabel={`Collapse ${labelTitle} threads`}
    onToggle={() => parentOptions.onToggleCollapsed(thread.id)}
    revealOnHover={!isParentCollapsed}
    />
  • Command registry:
    export const APP_COMMAND_IDS = [
    "palette.open",
    "thread.new",
    "thread.search",
    "thread.rename",
    "thread.archive",
    "thread.previous",
    "thread.next",
    ...THREAD_JUMP_APP_COMMAND_IDS,
    "pane.focus.previous",
    "pane.focus.next",
    ...PANE_FOCUS_APP_COMMAND_IDS,
    "pane.maximize.toggle",
    "pane.close",
    "window.new",
    "app.back",
    "settings.open",
    "settings.openServers",
    "sidebar.toggle",
    "panel.newTab",
    "panel.reopenClosedTab",
    "panel.close",
    "panel.toggle",
    "file.quickOpen",
    "diff.toggle",
    "terminal.open",
    "composer.focus",
    "modelPicker.toggle",
    "modelPicker.cycleModel",
    "modelPicker.cycleModelBackward",
    "modelPicker.cycleProvider",
    "modelPicker.cycleProviderBackward",
    "modelPicker.cycleReasoning",
    "modelPicker.cycleReasoningBackward",
    "browser.focusLocation",
    "browser.reload",
    "browser.find",
    "workspace.openPreferred",
    "logs.openServerDaemon",
    "notifications.open",
    ...QUESTION_SELECT_APP_COMMAND_IDS,
    ] as const;

Checked on bb desktop 0.42.1 from source at dba32a469fd820ff6106715db0aaf6ed297d79a5, macOS 15.7.7.

What you would expect

Add a bindable app command such as Toggle child threads for the selected parent thread.

  • It appears in Settings → Keyboard and the quick palette.
  • It can be unassigned by default; users can choose a shortcut.
  • It collapses the selected thread's children when expanded and expands them when collapsed.
  • It is unavailable, or safely does nothing, when the selected thread has no children.
  • It uses the existing persisted sidebar collapse state.

Context and alternatives

The current workaround is to use the pointer, or Tab through the sidebar until the disclosure button has focus. That works, but it interrupts keyboard thread navigation.

I searched open and closed issues and found no request for this command. #3195 concerns the size of the same disclosure control on mobile, not keyboard access.

Checks

  • I searched open and closed issues for the same request.
  • If an agent wrote this, the body ends with > AGENT GENERATED.

AGENT GENERATED

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

    uiApp shell, sidebar, composer, rendering

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions