Skip to content
Component installs need the registry setup
VegaStack Design

Space Picker

SpaceChip shows which space a record lives in; SpacePicker chooses it from a searchable list.

Status
stable
Since
0.23.116
Accessibility pattern
filterable listbox; disabled rows say why; Esc closes

Last updated

Install

Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Space Picker before installation. Retain the digest printed by this command.

pnpm exec vegastack-design verify space-picker

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/space-picker

Run the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.

The same command installs the registry items it composes: @vegastack/button, @vegastack/command, @vegastack/popover, @vegastack/space-avatar.

Usage

import { SpacePicker } from "@/components/ui/space-picker";

<DialogTitle className="flex items-center gap-1">
  <SpacePicker
    placement="title"
    spaces={writableSpaces}
    value={spaceId}
    onValueChange={setSpaceId}
  />
  <span aria-hidden className="text-muted-foreground">
    ›
  </span>
  <span>New task</span>
</DialogTitle>;

SpaceChip is a space as a quiet property chip: its tile, its name and a ▾, tinted on hover. SpacePicker is that chip opening a searchable list of the spaces you pass: "My space" first, then "Spaces", a check on the current one, and a disabled row that says why it cannot be chosen. placement="title" sizes the chip for a dialog title — [▣ General ▾] › New task; field sizes it for a form or a property row.

Scope

  • Owns: the chip, the list, search, the groups, the check and disabled reasons.
  • Does not own: which spaces a person may add to, or the default space — pass spaces and value.
  • Compose with: SpaceAvatar (it draws every tile) and Dialog titles.

Anatomy

SpaceChip — data-slot="space-chip" | "space-chip-chevron" | "space-chip-icon"
SpacePicker — data-slot="space-picker" | "space-picker-item"

Examples

In a form, and read-only on a card

readOnly (often size="xs") shows where a record lives without offering a change: plain text, no ▾, no tab stop. For a space the viewer cannot see, pass space={null} and a hint — { kind: "personal", ownerName } reads "Priya's My space" with a person-with-lock, { kind: "private" } reads "Private space" with a lock. The hint never names the space itself.

ProductMy space

API Reference

PropTypeDefaultDescription
spaces*readonly SpacePickerItem[]—The spaces to offer, in order; personal spaces are listed first, under "My space".
classNamestring—Classes for the chip.
disabledbooleanfalseDisable the chip.
onOpenChange((open: boolean) => void)—Called when the list opens or closes.
onValueChange((id: string) => void)—Called with the chosen space's id; the list then closes.
openboolean—Controlled open state of the list.
placeholderReact.ReactNode"Choose a space"Shown on the chip while nothing is chosen.
placement"field" | "title""field"title — the chip sized for a dialog title, beside "› New task". field — the chip sized for a form or property row.
valuestring | null—The chosen space's id.

Data attributes and CSS variables on SpacePicker

AttributeValues
data-checked"true"
data-slot"space-picker" | "space-picker-item"

SpacePickerItem

PropTypeDefaultDescription
id*string—The space's id — what value and onValueChange carry.
space*Space—The space, drawn with SpaceAvatar. access: "personal" lists it under "My space".
disabledstring | booleanfalseShown but not choosable. A string says why, on the row: "You can view, not add, here".
secondaryReact.ReactNode—A muted second line, such as "Private · 8 members".

SpaceChip

PropTypeDefaultDescription
hintSpaceHint | null—With no space: which kind of space the viewer cannot see holds the record — shows "Priya's My space" or "Private space" with its glyph.
placeholderReact.ReactNode"Choose a space"Shown while there is no space.
readOnlybooleanfalseShow where the record lives without offering a change: plain text, no ▾, no tab stop.
size"sm" | "title" | "xs""sm"xs — 24px, small text and a 16px tile (a card or a dense row). sm — 28px, body text and a 20px tile (a form or a property row). title — the dialog title's type size.
spaceSpace | null—The space shown; empty shows hint, else placeholder with the generic space glyph.

Data attributes and CSS variables on SpaceChip

AttributeValues
data-empty""
data-icon"inline-end"
data-readonly""
data-sizemirrors a prop or state value
data-slot"space-chip" | "space-chip-chevron" | "space-chip-icon"

Accessibility

  • The chip is a button named "Space: General" ("Space: none chosen" while empty), so a title that holds it still reads in order.
  • The list is a filterable listbox; the current space is checked, and a disabled row's reason is its visible second line.
KeyAction
Enter / SpaceOpen the list; pick a space
TypingFilter the list
↑ / ↓Move between spaces
EscClose without changing
ContractStates tested
Behaviourclosed, open, checked, disabled-reason, filtered, empty, read-only, hidden-space
Accessibilitylabeled, keyboard, browser-accessibility-test
Visualdefault, hover, focus

Do / Don't

Do
List only the spaces the person can add to, and say why a visible one is disabled.
Don't
Put the space in a form field below the title when the dialog creates something in a space.

On this page