component

ListBox

props · 30 shown · 30 total

State

  • boolean
    default false

    Render the loading row instead of the options.

Appearance

  • "primary" "secondary" "tertiary" "highlight"
    default "secondary"

    How loud the CHOSEN row is — the same vocabulary Panel, Navigation and TreeView use, applied to whatever this list marks as chosen: the selected options of a listbox, and the checked checkbox / radio items of a menu. `"secondary"` (the default) is the recessed well framed by a muted border. `"primary"` fills the row with the accent surface and flips its text to the contrast ramp — by far the most legible, and the one to reach for when the chosen row has to read at a glance in a dense list. `"tertiary"` is the same recess pinned to the colorless neutral ramp. This is the LOUDNESS axis only — {@link ListBoxBaseProps.activeTone} picks the color, so a neutral list can carry a brand-coloured chosen row.

  • "inherit" "cyan" "danger" "dynamic" "mauve" "neutral" "pink" "primary" "sage" "slate" "stone" "success" "teal" "violet" "warning"
    default "inherit"

    Which palette the CHOSEN row paints with, independent of the list's own `tone`. That independence is the point: a neutral list — rows that read as text, not links — can still mark its current row in brand color without dragging every other row's hover and muted text onto the brand ramp. Defaults to `"inherit"` — the chosen row follows the list, so a `tone="danger"` list gets a red chosen row. Set it to split the two apart: `tone="neutral"` with `activeTone="primary"` is a plain list whose current row is brand blue. Only the filled row (`activeEmphasis="primary"`) reads this; the quiet levels are a recess on the list's own ramp by definition.

  • "transparent" "surface.peak" "surface.hill" "surface.base" "surface.valley" "surface.ground"
    default "surface.peak"

    Surface ramp step the list's panel paints (`emphasis` picks the concrete ramp). The list is a floating, elevated surface, so it rests on the lightest step.

  • "none" "default" "bold" "muted" "accent"
    default "muted"

    Resting border color of the list surface.

  • false CardFrameProps<TSlot>
    default {}

    The Card the list renders itself in. A standalone ListBox is card-based: it always renders its own Card, configured by this prop — surface props (`background`, `border`, `radius`, `contentBackground` for an inset panel…), a `heading` / `subheading` / `eyebrow`, header `leading` / `trailing` actions and a `footer`. The list's own surface props (`background`, `emphasis`, `tone`, `border`, `radius`, `shadow`, `translucent`) become the Card's defaults, so a ListBox with no card props looks like the bare list. `card.heading` labels the list: the `<ul role="listbox|menu">` gets `aria-labelledby` pointing at the rendered heading unless `aria-label` / `aria-labelledby` is passed. `false` renders the bare list (no Card) — the escape hatch composites (Select, Combobox, Menu, Command palette) use for their popup lists.

  • "start" "end"
    default "end"

    Which edge of the row the check column sits on. end: after the label and any shortcut / trailing content — labels keep the panel edge, with no empty leading column on unchosen rows. start: before the label.

  • "primary" "secondary" "tertiary"
    default "secondary"

    How loud the list's surface is. `"secondary"` keeps the list on the `colorPalette` ramp — the tinted-but-quiet surface every popup uses.

  • "none" "sm" "md" "lg" "inherit" "2xl" "xl" "xs" "2xs" "3xl" "4xl" "5xl" "6xl" "inner" "full"
    default "md"

    Corner radius of the list surface. The option rows track it automatically (their corner is the concentric step down from this one). Inside a popover the list sits under a transparent `xl` dialog, so `"inner"` resolves against that dialog rather than the trigger — pass an explicit value there (Select / Combobox / Menu expose `listboxRadius` for exactly this).

  • "none" "sm" "md" "lg" "inherit" "2xl" "xl" "xs" "2xs" "3xl" "4xl" "5xl" "6xl" "inner" "full"

    Override the two bottom corners.

  • "none" "sm" "md" "lg" "inherit" "2xl" "xl" "xs" "2xs" "3xl" "4xl" "5xl" "6xl" "inner" "full"

    Override the two left corners.

  • "none" "sm" "md" "lg" "inherit" "2xl" "xl" "xs" "2xs" "3xl" "4xl" "5xl" "6xl" "inner" "full"

    Override the two right corners.

  • "none" "sm" "md" "lg" "inherit" "2xl" "xl" "xs" "2xs" "3xl" "4xl" "5xl" "6xl" "inner" "full"

    Override the two top corners (a list flush under a search field).

  • "none" "sm" "md" "lg" "xl" "xs"
    default "none"

    Elevation of the list surface. Floating usages (menu / select / combobox / command-palette popups) get `lg` from the recipe's `[data-popover]` rule regardless — an inline list is unshadowed unless you ask.

  • "soft" "framed" "separate" "plain"
    default "soft"

    How every row's `shortcut` renders (KbdGroup `appearance`). soft: quiet square keys on a subtle fill (the default). framed: one rounded frame per chord holding compact caps. separate: loose caps. plain: text only.

  • boolean
    default false for `pattern="listbox"`, true for `pattern="menu"`

    Whether the list draws the check column — a reserved-width leading indicator revealed on the chosen rows. The default depends on the pattern. A `"listbox"` is off: selection reads through `aria-selected` and the selected surface alone, and value-selection controls (Select, Combobox) opt in. A `"menu"` is on: its checkable rows (`menuitemcheckbox` / `menuitemradio`) carry the glyph, and every row of the same segment reserves the column so nothing shifts when one is checked. Pass it explicitly to override either default. `false` on a menu drops the glyph AND the reserved column, so every label sits flush — worth it when the chosen row is already a filled surface (`activeEmphasis="primary"`), where the fill says "chosen" and the glyph is an indent every row pays for. Purely visual: `aria-checked` / `aria-selected` are unaffected either way. On a listbox it still needs something to indicate — no effect when `selectionMode` is `"none"`.

  • "sm" "md" "lg"
    default "md"

    Visual size variant — controls option row height/padding (and the empty/loading status text size). Option text itself keeps one size across variants (the rows render an `xs` Banner).

  • "cyan" "danger" "dynamic" "mauve" "neutral" "pink" "primary" "sage" "slate" "stone" "success" "teal" "violet" "warning"
    default "neutral"

    Semantic surface color (surfaces / border / text).

  • boolean
    default false

    Blur + saturate whatever shows through the list's surface.

Layout

  • "none" "sm" "md" "lg" "2xl" "xl" "xs" "10xl" "11xl" "2xs" "3xl" "3xs" "4xl" "4xs" "5xl" "6xl" "7xl" "8xl" "9xl"
    default "none"

    The list's own padding. `"none"` by default: the inner scroller pads itself so the scrollbar sits inside the padding. The recipe still publishes that real inset to nested panels, so `radius="inner"` children (the option rows included) compute the right concentric corner.

Behavior

  • "roving" "active-descendant"
    default "roving"

    Keyboard-cursor model. `"roving"` (the default) lets the list own DOM focus — the focused option becomes the tab stop and real focus moves onto it. `"active-descendant"` keeps DOM focus on an external control (e.g. a command-palette / combobox `<input>`): options omit `tabindex`, the cursor is surfaced via `data-focused` + the focused option's `id` (for the control's `aria-activedescendant`), and navigation is driven from outside.

  • items required
    ListBoxNodeInput[]

    The list's data, in render order. An option is `{ id, label, description?, eyebrow?, leading?, trailing?, textValue?, disabled? }` (label/description/ eyebrow map onto the row's Banner; leading/trailing render in the row's affix wrappers, Button-style); a section is `{ id, type: "section", title?, header?, items }`; a divider is `{ id, type: "separator" }`; a non-interactive content block is `{ id, type: "custom", content? }`.

  • "listbox" "menu"
    default "listbox"

    The ARIA pattern the list renders as. `"listbox"` (default) is a value-selection list; `"menu"` renders `role="menu"` + `menuitem` semantics for action menus (consumed by the Menu component).

  • boolean
    default false

    Serialize the list surface's resolved panel inputs into `data-panel-config` so `updatePanelElement()` can restyle it at runtime without a framework (Astro / vanilla JS).

  • "immediate" "deferred"
    default "immediate"

    When the keyboard cursor first appears (active-descendant mode): - `"immediate"` (default): the first `ArrowDown`/`ArrowUp` lands on (and shows) the first/last option right away. Right for a standalone list or a command palette where the popup only exists once the user is navigating. - `"deferred"`: the first arrow *reveals* a pre-seated cursor (on the selected option, else the first/last by direction) **without stepping**; only subsequent arrows step. This is the ARIA combobox behavior — the cursor + `aria-activedescendant` stay hidden until the user navigates.

  • "none" "single" "multiple"
    default "single"

    How clicks / Enter / Space resolve into a selection. `"none"` is a command-palette style list that activates but never persists a selected state.

  • "auto" "mac" "other"
    default "auto"

    Which platform's labels the row shortcuts use (`mod` → ⌘ on mac, Ctrl elsewhere) — also the platform `aria-keyshortcuts` resolves `mod` for. auto: the detected platform (`detectedPlatform`), mac until one is detected.

Advanced

  • "mac" "other"

    The viewer's platform, as `detectPlatform()` from `@pindoba/core-kbd` reports it after mount. Used only when `shortcutPlatform` is "auto".

  • ListBoxPassThrough

    Per-slot escape hatch to inject Panda styles or HTML attributes into any slot of the component.

  • RootAttributes

    Extra HTML attributes spread onto the root `listbox` element.

Plus all standard <ul> HTML attributes.

Type

  • Components
  • Blocks