elements icon indicating copy to clipboard operation
elements copied to clipboard

Single Select dropdown closes on scroll

Open dankeboy36 opened this issue 4 months ago • 2 comments

When I use <vscode-single-select>, the dropdown closes whenever the surrounding content scrolls.

In my app I have a terminal (xterm.js) under a toolbar. The select is in the toolbar and stays visible, but when the terminal prints new lines and scrolls, the dropdown closes.


The attached code is a minimal repro without xterm: it just appends lines to a div and scrolls the page. The result is the same; the dropdown closes by itself when scrolling happens.

https://github.com/user-attachments/assets/e4f9838e-3a20-4bdd-85e7-d5341b38235e

import {
  VscodeOption,
  VscodeSingleSelect,
} from '@vscode-elements/react-elements'
import { useEffect, useRef } from 'react'
import { createRoot } from 'react-dom/client'

function Repro() {
  const contentRef = useRef(/** @type {HTMLDivElement | null} */ (null))

  useEffect(() => {
    const el = contentRef.current
    if (!el) return

    // seed
    for (let i = 0; i < 30; i++) {
      const d = document.createElement('div')
      d.textContent = `line ${i + 1} — seed`
      el.appendChild(d)
    }

    const id = setInterval(() => {
      const div = document.createElement('div')
      div.textContent = `line ${el.children.length + 1} — ${new Date().toLocaleTimeString()}`
      el.appendChild(div)

      window.scrollTo({ top: document.documentElement.scrollHeight })

      const selectEl = document.getElementById('demo-select')
      const open = !!(
        selectEl &&
        (selectEl.hasAttribute('open') || selectEl.open === true)
      )
      console.log('[append]', { open })
    }, 700)
    return () => clearInterval(id)
  }, [])

  useEffect(() => {
    const el = document.getElementById('demo-select')
    if (!el) return
    const log = () =>
      console.log(
        '[select] open =',
        el.hasAttribute('open') || el.open === true
      )
    const mo = new MutationObserver(log)
    mo.observe(el, { attributes: true, attributeFilter: ['open'] })
    log()
    return () => mo.disconnect()
  }, [])

  return (
    <div>
      <div style={{ position: 'sticky', top: 0 }}>
        <VscodeSingleSelect id="demo-select" name="demo">
          <VscodeOption value="">Pick one…</VscodeOption>
          <VscodeOption value="1">Option 1</VscodeOption>
          <VscodeOption value="2">Option 2</VscodeOption>
          <VscodeOption value="3">Option 3</VscodeOption>
        </VscodeSingleSelect>
      </div>
      <div ref={contentRef} />
    </div>
  )
}

const root = document.getElementById('root')
createRoot(root).render(<Repro />)

Expected: Dropdown stays open until I close it. Actual: Dropdown closes automatically on scroll.


Update: Maybe related #453?


Update2:

As a comparison, native <select> disables the scroll when the popover is visible (on macOS):

https://github.com/user-attachments/assets/92391783-62b9-4006-9c5e-7274ccb8173f

react-select lets the page scroll with an open popover:

https://github.com/user-attachments/assets/27198a7f-3b71-4219-8f1e-ab8fb1c7e9c8

<vscode-single-select> closes the popover on page scroll:

https://github.com/user-attachments/assets/91fbb250-ef6e-4560-87de-3240aa02ced7

dankeboy36 avatar Sep 01 '25 13:09 dankeboy36

I recently rewrote the select components using the Popover API. The problem is the dropdown position is fixed, so it stays in a place while the rest of the page is scrolling. I like the solution of the mac os.

bendera avatar Sep 01 '25 19:09 bendera

@dankeboy36 I wasn't able to reproduce this bug, but I made a possible fix. I added an extra condition that check whether component has actually moved, and only then closes the dropdown. Could you try it?

  • Checkout this branch: 514-select-dropdown-closes-on-scroll
  • Run npm run build
  • Link the package to your project. Run the npm link command in the vscode-elements directory. Then run the npm link @vscode-elements/elements command in your project.

Related PR: #527

bendera avatar Sep 06 '25 21:09 bendera