Skip to content

Select multiple: Space requires 2+ presses to toggle items (double-call in keydown) #2049

Open

Description

@SaraKaminska

Describe the bug

In Select.Root with type="multiple", pressing Space on a highlighted item does not reliably toggle selection on the first press. The trigger's keydown handler calls handleKeyboardSelection() twice within a single Space press — once in the early SPACE-selection branch and once in the typeahead-fallback branch — yielding a net no-op (toggle on → toggle off) for multi-select.

Single-select is unaffected because it returns early after the first call.

Steps to reproduce

This issue can be reproduced in the example in the docs.

  1. Render a <Select.Root type="multiple"> with at least two items whose textContent contains spaces, e.g. "Chocolate", "Cherry".
  2. Tab focus to the trigger.
  3. Press Enter or Space to open the dropdown.
  4. Press ArrowDown to highlight an item.
  5. Press Space once.

Expected

The highlighted item toggles selected/deselected on the first Space press.

Actual

Nothing visibly happens. A second (sometimes third) Space press is needed before a toggle "sticks". Click and Enter both work correctly — only Space is affected.

Root cause

In SelectTriggerState.onkeydown (src/lib/bits/select/select.svelte.ts, around the onkeydown for the trigger state), Space falls through two handler branches:

Branch 1 — early SPACE-selection:

if ((e.key === kbd.ENTER || (e.key === kbd.SPACE && this.#domTypeahead.search === "")) && !e.isComposing) {
  e.preventDefault();
  const shouldReturn = this.#handleKeyboardSelection();
  if (shouldReturn) return;
}

For multi-select, handleKeyboardSelection() returns false (no auto-close), so execution falls through.

Branch 2 — typeahead fallback (further down the same function):

if (!isModifierKey && (isCharacterKey || isSpaceKey)) {
  const matchedNode = this.#domTypeahead.handleTypeaheadSearch(e.key, candidateNodes);
  if (!matchedNode && isSpaceKey) {
    e.preventDefault();
    this.#handleKeyboardSelection();
  }
  return;
}

handleTypeaheadSearch(" ", …) appends " " to the search buffer. getNextMatch(values, " ", currentMatch) returns undefined (no item starts with " "), so !matchedNode && isSpaceKey evaluates true and handleKeyboardSelection() is called again, reverting the toggle from Branch 1.

Single-select isn't hit because Branch 1 returns true from handleKeyboardSelection (auto-close path), short-circuiting before Branch 2.

Suggested fix

After Branch 1 fires for SPACE in multi-select, return so Branch 2 doesn't run. Either:

if ((e.key === ENTER || (e.key === SPACE && this.#domTypeahead.search === "")) && !e.isComposing) {
  e.preventDefault();
  const shouldReturn = this.#handleKeyboardSelection();
  if (shouldReturn) return;
  if (e.key === SPACE) return; // ← also return after multi-select SPACE selection
}

Or track a handledBySpace flag and skip the typeahead branch when set. Happy to open a PR.

Workaround

Intercept Space in capture phase on the trigger, toggle the value directly, and stopImmediatePropagation to block the buggy handler. (Verified working in our codebase.)

Reproduction

https://stackblitz.com/run?file=src%2Froutes%2F%2Bpage.svelte&terminalHeight=10

Logs

System Info

System:
    OS: Windows 10 10.0.19045
    CPU: (16) x64 Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz
    Memory: 2.74 GB / 15.85 GB
  Binaries:
    Node: 24.4.0 - C:\nvm4w\nodejs\node.EXE
    npm: 11.12.0 - C:\nvm4w\nodejs\npm.CMD
    pnpm: 10.13.1 - C:\Users\sarak\AppData\Local\pnpm\pnpm.EXE
    bun: 1.3.13 - C:\Users\sarak\.bun\bin\bun.EXE
  Browsers:
    Chrome: 147.0.7727.138
  npmPackages:
    @sveltejs/kit: ^2.57.0 => 2.57.1
    bits-ui: ^2.17.3 => 2.17.3
    svelte: ^5.55.2 => 5.55.3

Severity

annoyance

Activity

  1. added
    triageA maintainer needs to review this issue and label it appropriately
    on May 11, 2026
  2. added and removed
    triageA maintainer needs to review this issue and label it appropriately
    on May 22, 2026
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

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions