---
id: STATE-PFM-CSH-004
title: Side menu fold
object: DOM-PFM-CSH-001
product_area: platform
module: console-shell
revision: 1
status: draft
design_intent: confirmed
origin: >-
  react-console:docs/page-layouts.md#Pages that collapse the sidebar (2026-10-12
  final acceptance, accepted by Andrew)
implementation_evidence: observed
source_sha:
  react-console: baf6dae382d6f41dce976c7f848667ccc37e076f
states:
  - name: expanded
    meaning: The desktop sidebar displays its full navigation width.
  - name: collapsed
    meaning: The desktop sidebar presents its compact icon rail.
  - name: collapsed-by-page
    meaning: >-
      A page that found the sidebar open has closed it and will restore it on
      unmount.
transitions:
  - from: expanded
    to: collapsed
    trigger: The desktop toggle or menu shortcut closes the sidebar.
    guard: No additional guard.
    side_effects:
      - Write the desktop fold choice to the sidebar cookie.
    who: person
    provenance: test
    source: >-
      react-console:e2e/layout/page-layouts.spec.ts#the keyboard shortcut
      collapses it too
  - from: collapsed
    to: expanded
    trigger: 'The desktop toggle, shortcut or rail selection opens the sidebar.'
    guard: No additional guard.
    side_effects:
      - A rail selection also selects the opened section.
    who: person
    provenance: observed
    source: 'react-console:components/console/app-sidebar.tsx:NavSectionItem'
  - from: expanded
    to: collapsed-by-page
    trigger: A collapsing page mounts while the sidebar is open.
    guard: The arrival snapshot records an open sidebar.
    side_effects: []
    who: console
    provenance: documented
    source: 'react-console:docs/page-layouts.md#Pages that collapse the sidebar'
  - from: collapsed-by-page
    to: expanded
    trigger: The page that scheduled restoration unmounts.
    guard: Restoration was scheduled when the page mounted.
    side_effects: []
    who: console
    provenance: observed
    source: 'react-console:components/console/collapse-sidebar.tsx:CollapseSidebar'
  - from: collapsed-by-page
    to: expanded
    trigger: The person opens the sidebar before the collapsing page unmounts.
    guard: The page remains mounted and its arrival snapshot was open.
    side_effects:
      - Unmount still restores open state based on the arrival snapshot.
    who: person
    provenance: inferred
    source: >-
      react-console:components/console/collapse-sidebar.tsx:CollapseSidebar
      (restore on unmount)
invalid:
  - from: collapsed
    to: expanded
    why: >-
      The page arrived with a closed menu and therefore schedules no open-state
      restoration.
concurrency: >-
  The sidebar writes a cookie on open-state changes, but the shell does not read
  it to initialize the next load. Each tab holds its own fold. Mobile navigation
  uses a separate open state within SidebarProvider.
evidence:
  - >-
    react-console at baf6dae: components/ui/sidebar.tsx (SidebarProvider,
    SIDEBAR_KEYBOARD_SHORTCUT);
    components/console/{collapse-sidebar,app-sidebar,console-shell}.tsx;
    docs/page-layouts.md.
---
# Side menu fold

## The Lifecycle

```mermaid
stateDiagram-v2
  [*] --> expanded
  expanded --> collapsed: desktop close
  collapsed --> expanded: desktop open
  expanded --> collapsed_by_page: collapsing page mounts
  collapsed_by_page --> expanded: restoring page unmounts
```

## Transitions Explained

The sidebar is expanded by default. The desktop toggle or shortcut folds it, and choosing a rail section expands it. CollapseSidebar remembers whether the menu was open on arrival, folds it if needed and restores it on unmount.

## What Cannot Happen

A page reached with the sidebar already closed does not schedule restoration. The restoring page does not track later manual preferences: if it originally folded an open menu, unmount sets it open again.

## Concurrency and Timing

The sidebar writes a cookie on open-state changes, but the shell does not read it to initialize the next load. Each tab holds its own fold. Mobile navigation uses a separate open state within SidebarProvider.
