Skip to content

Components · Identity

SpaceSwitcher

Pick "All spaces" or one Space of the workspace, with search, New and Manage links.

@rookcom/monarch-react/shellComponent

All spaces, with New and Manage

Usage examples

Collapsed, and without All spaces

Purpose

Rook workspaces are split into Spaces (department-like slices managed in Rook ID). The switcher sets which Space the app shows. Its listbox supports arrow-key navigation.

Use when

  • An app that scopes its content by Space, in the rail’s spaceSwitcher slot or a page header.

Avoid when

  • Switching workspaces: use WorkspaceSwitcher.
  • Filtering a single list by team or department: use a filter in FilterBar.

Design principles

  • Data in, choice out: the app passes the Spaces this person may open and stores the choice; the switcher never fetches or persists.
  • One listbox model (EntityPicker): arrow keys, Home/End, type to search, Enter to choose, Escape to close; options are real options, not buttons.
  • "All spaces" is a first-class choice, shown first and checked when nothing is chosen.
  • A Space that disappears (deleted, access removed) reads as "All spaces" instead of a stale name.

API reference

import { SpaceSwitcher } from '@rookcom/monarch-react/shell';
ExportKindRenderingRoot class
SpaceSwitchercomponentclient.mn-space-switcher

Forwards its ref to the trigger button. Built on EntityPicker from @rookcom/monarch-react.

SpaceOption is { id, name, description?, icon? }.

Generated from the TypeScript declarations of packages/react/src/components/identity/space-switcher.

Properties

value is a Space id or null for "All spaces"; controlled with value + onValueChange, or uncontrolled with defaultValue.

manageHref opens in a new tab unless manageExternal={false}; onCreate or createHref adds "New Space".

SpaceSwitcher

Chooses the Space (a department-like slice of a workspace) the app shows: "All spaces" or one Space. A popover with search, the current Space checked, and New / Manage links; the list is a listbox with arrow keys, Home/End and type-to-search (EntityPicker). The product supplies the Spaces and stores the choice; the switcher never fetches.

PropTypeDescription
spaces requiredSpaceOption[]The Spaces of the current workspace that this person can open.
align"center" | "start" | "end"Popover alignment. Default `start`.
allowAllbooleanOffer "All spaces" first. Default true. Without it a Space must stay chosen.
classNamestring
collapsedbooleanIcon-only trigger for a collapsed rail; the name moves into a tooltip.
createHrefstring"New Space": a link…
defaultValuestring | null
hideWhenEmptybooleanRender nothing when there are no Spaces and nothing is loading. Default true.
loadingbooleanSpaces are still loading: the list says so.
manageExternalbooleanOpen `manageHref` in a new tab. Default true.
manageHrefstring"Manage Spaces" link (usually Rook ID).
messagesPartial<SpaceSwitcherMessages>Interface text, for translation.
onCreate(() => void)…or an action (the popover closes first).
onOpenChange((open: boolean) => void)
onValueChange((spaceId: string | null) => void)
openbooleanOpen (controlled).
valuestring | nullThe chosen Space id; `null` is "All spaces" (controlled).

Variants

PropValuesDescription
collapsed'false''true'Icon-only trigger with the current Space in a tooltip, for the 48px rail.
allowAll'true''false'Offer "All spaces". Without it a Space must stay chosen.

States

StateExposed asBehaviour
All spacesdata-allNothing chosen: the trigger reads "Space: All spaces".
Current Spacearia-selected="true"Checked in the list and named on the trigger.
Loading–The list says "Loading spaces…" while loading.
Empty–With no Spaces and nothing loading the switcher renders nothing (hideWhenEmpty), as the products did.
Openaria-expanded="true"On the trigger.

Interaction behaviour

  • Clicking the trigger (or Enter, Space, ↓) opens the popover with focus in the search box.
  • Typing filters by name; choosing closes the popover and returns focus to the trigger.
  • "New Space" closes the popover, then runs onCreate (or follows createHref); "Manage Spaces" opens Rook ID in a new tab.

Keyboard support

KeysAction
Enter / Space / ↓Open the popover from the trigger.
↓ / ↑Move through the Spaces.
Home / EndFirst / last Space.
EnterChoose the highlighted Space.
TabFrom the search box to New / Manage.
EscapeClose and return focus to the trigger.

Accessibility

Role
button opening a dialog that contains a combobox (search) and a listbox
Accessible name
The trigger is "Space: <current>" (messages.label); the popover is named "Space".
  • Follows the APG combobox pattern with a listbox popup (EntityPicker); the active option is tracked with aria-activedescendant.
  • The collapsed trigger keeps its full name and adds a tooltip.
  • The Manage link announces that it opens in a new tab.

Responsive behaviour

  • The trigger fills its container and truncates long names.
  • The popover is 18rem wide, never wider than the screen minus 2rem; New / Manage rows are 44px tall on touch screens.

Theme support

  • Surface, border and text tokens; inside RookRail the trigger switches to the accent panel colours.
  • Transitions are removed under reduced motion.

Do and don't

Do

  • Pass only the Spaces this person may open, and still check access on the server.
  • Remember the choice per workspace in the app (Rook apps share it across apps).
  • Use the rail slot function to pass collapsed.

Don't

  • Do not fetch Spaces inside a slot render on every render; load them once and pass the list.
  • Do not use it for navigation between pages.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsEntityPicker

Testing coverage

  • Trigger named with the current Space; starts on All spaces.
  • Popover with search focused, the current Space selected and the Manage link.
  • Typing filters; arrow keys and Enter choose; focus returns to the trigger.
  • All spaces clears the choice; allowAll={false} hides it; controlled mode; a missing Space reads as All spaces.
  • New Space runs after closing; Escape returns focus; hidden when empty, loading message; collapsed tooltip; translation.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery/space-switcher; Cross-browser axe: /components/space-switcher

Tests: packages/react/src/components/identity/space-switcher