react-spectrum icon indicating copy to clipboard operation
react-spectrum copied to clipboard

ListBox always empty when rendered inside a ComboBox with a Modal instead of a Popover

Open nkalpak opened this issue 1 year ago โ€ข 12 comments

Provide a general summary of the issue here

When rendering something like this

  <ComboBox>
    {/* Note the Modal here instead of Popover */}
    <Modal>
      <ListBox>
        <ListBoxItem>One</ListBoxItem>
      </ListBox>
    </Modal>
  </ComboBox>

two issues arise:

  1. Without passing shouldCloseOnBlur={false} and allowsEmptyCollection={true} to the ComboBox, the Modal immediately closes upon opening. This is fine except that neither of these props are in the ComboBox's interface
  2. When passing these two props, the Modal now doesn't close, but the ListBox is empty, despite there being a static collection passed to it (see picture, the input is focused, modal is opened, but the listbox is empty) Screenshot from 2024-03-07 13-24-20

๐Ÿค” Expected Behavior?

  1. shouldCloseOnBlur and allowsEmptyCollection should be in the ComboBox's props interface
  2. The ListBox should render its items even when inside a modal

๐Ÿ˜ฏ Current Behavior

  1. shouldCloseOnBlur and allowsEmptyCollection are not in the interface
  2. The ListBox has an empty collection despite there being items passed to it

๐Ÿ’ Possible Solution

No response

๐Ÿ”ฆ Context

No response

๐Ÿ–ฅ๏ธ Steps to Reproduce

CodeSandbox

The sandbox uses the ComboBox as per the example in the react-aria-components docs.

You can try removing one or both of shouldCloseOnBlur/allowsEmptyCollection to see the first issue. You can leave both to see the second issue. You can try replacing the Modal with Popover in ComboBox.tsx:43, to verify that it works with a Popover but not Modal.

Version

[email protected]

What browsers are you seeing the problem on?

Firefox, Chrome, Safari, Microsoft Edge

If other, please specify.

No response

What operating system are you using?

Ubuntu

๐Ÿงข Your Company/Team

No response

๐Ÿ•ท Tracking Issue

No response

nkalpak avatar Mar 07 '24 12:03 nkalpak

Doesn't look like I can access your CodeSandbox, perhaps due to permissions? As for using a ComboBox with a Modal, that isn't a supported use case, at least not yet. Internally, the ComboBox sends a variety of things that its internal aria hook uses such as refs and isNonModal via a context that Popover consumes which won't work with Modal. Accessibility wise, these are needed since we typically hide everything outside of a overlay from screen readers but ComboBox's dropdown is an exception here since focus remains in the input element at ALL times and thus the screen reader user needs to be able to interact with the input element AND the contents of the Popover.

This isn't setup to work with a Modal however, hence the blur that happens when focus moves from the input into the Modal, resulting in the ComboBox closing as you've noticed. I'll need to look into why the ListBox is empty even when you force the Modal to remain open, but ideally we'd want to support ComboBox + Modal as a whole since there will be a host of other issues other than that. To support this use case, I imagine we'd need to do something like RSP ComboBox does for its mobile case where it renders a Tray with a combobox inside of said Tray to get around the "hide all elements outside the Modal" problem.

LFDanLu avatar Mar 08 '24 22:03 LFDanLu

I just updated the permissions on the sandbox, I guess now you need to make it public explicitly.

RSP ComboBox does for its mobile case where it renders a Tray with a combobox inside of said Tray

Yep, this is pretty much my use-case too. I want to use the Popover on desktop but a full width/height Modal on mobile.

nkalpak avatar Mar 11 '24 06:03 nkalpak

Gotcha, the team wants to set something up for in RAC for mobile Tray support so this will most likely be part of that effort. No ETA on that yet however.

LFDanLu avatar Mar 11 '24 17:03 LFDanLu

I understand that Modal is not supported for Combobox, but why it's also the case for Select?

mehdibha avatar May 24 '24 16:05 mehdibha

Linking the issue you created @mehdibha https://github.com/adobe/react-spectrum/discussions/6409 and I'll close out the discussion

snowystinger avatar Jul 10 '24 04:07 snowystinger

I have the same use case with Select. Basically, I already have a modal dialog component that visually behaves like a tray on mobile, and I want to use it for the select's options on mobile. However, since the list box isn't always rendering, the Select thinks it doesn't have any items.

I noticed this works in React Spectrum's Picker component. What's the magic sauce that makes it work there? ๐Ÿ‘€

jeffijoe avatar Mar 30 '25 11:03 jeffijoe

It would be cool if it was possible to explicitly pass a collection slot value via context.

For example, if I have a MySelectWrapper component that does some things that mess with collection propagation, if I could explicitly do

<CollectionProvider items={props.items} children={props.children}>
  <RACSelect {...props}>
     {my select implementation}
  </RACSelect>
</CollectionProvider>

Then the Aria components should theoretically be able to use those, no?

jeffijoe avatar Mar 30 '25 12:03 jeffijoe

What's the magic sauce that makes it work there?

This is probably relevant to how the Picker works. It seems like they keep the list in memory regardless of whether the thing is open or not.

Also from my experience building a ComboBox with a mobile tray, I found it easier to work at the hook level (react-aria) rather than the component level (react-aria-components). I found the components to be too difficult to wrangle together for that use case

nkalpak avatar Mar 31 '25 07:03 nkalpak

I think the useListBoxLayout is for virtualizing, not necessarily collection management - thanks though!

I tried to use useSelect but could not make it work with a RAC ListBox, and I was hoping to avoid having to drop down to hooks for the list box because the RAC listbox also integrates with the auto-complete.

jeffijoe avatar Mar 31 '25 08:03 jeffijoe

I think the useListBoxLayout is for virtualizing, not necessarily collection management - thanks though!

Ah yes! Then it's a few lines down, rendering the ListBoxBase which then has the collection management inside.

nkalpak avatar Mar 31 '25 09:03 nkalpak

Thanks @nkalpak - I had seen that as well, and have attempted something similar, but I've spent well over a week trying to get this to work with no luck, so I'm gonna have to admit defeat and use a popover.

jeffijoe avatar Mar 31 '25 13:03 jeffijoe

I noticed this works in React Spectrum's Picker component. What's the magic sauce that makes it work there? ๐Ÿ‘€

Picker is using the hooks, it hasn't been migrated to RAC yet.

The magic sauce in Popover is this: https://github.com/adobe/react-spectrum/blob/79505ba223825b329cdba614f3c1ff1cd7f89659/packages/react-aria-components/src/Popover.tsx#L100-L114

Basically, this renders the children into a hidden DOM tree even when the popover is not open. That way it can collect the items into the collection, and features like typeahead works on the Select while it is closed. Modal could probably support something similar.

devongovett avatar May 29 '25 00:05 devongovett

Basically, this renders the children into a hidden DOM tree even when the popover is not open. That way it can collect the items into the collection, and features like typeahead works on the Select while it is closed. Modal could probably support something similar.

@devongovett is it possible to work around this with RAC somehow?

jeffijoe avatar Jun 25 '25 16:06 jeffijoe