[Bug] disabled in select option does not work

For native select elements, setting the disabled attribute on an option has no effect:

<select>
<option disabled>...</option>
</select>

Btw, is the forum the right place to submit such bugs? I thought about creating issues on github, but there are only repos dedicated to either the documentation or the examples, so I didn’t think it would fit there.

Just to piggyback on this, I’ve also found that the “multiple” attribute on native select elements doesn’t work.

<select name="cars" id="cars" multiple>
      <option value="volvo">Volvo</option>
      <option value="saab">Saab</option>
</select>

The HTML <select> does not support disabled or multiple. If you need this functionality, please use sp-dropdown, which supports both features.

1 Like

Hint for everyone: the multiple property has to go on the sp-menu, not the sp-dropdown.

Also, @kerrishotts , is there any way of keeping the dropdown opened, when selecting multiple items?
Feels like bad UX when the user has to open the dropdown 10 times to select 10 items. Maybe the component should listen for CTRL or meta-key press inside.

The whole multiple-dropdown thing took me a while to figure out correctly, so I’ll quickly share my learnings here for anyone else running into these issues.
I’m still getting a bit confused by the fact that Spectrum is praised and recommended to be used while there’s so little documentation on it (the actual UXP implementation) that we kind of have to fish in muddy waters.

Anyways, the UXP examples show the use of onChange(evt => console.log(evt.target.selectedIndex) to retrieve the index of the selected item. For multiple selectable options (sp-menu-items), this doesn’t help a lot as it always returns the index of the first selected option.

Logging evt.target.__proto__ finally gave me an idea of which properties the sp-dropdown object actually has:

image

So at least there’s a getter called selectedOptions, which returns the sp-menu-item elements whose values we can the retrieve and parse.

If you’re using React, you’re probably storing selected options in some kind of state. In my case it looks like this:

const state = {
  someObj: {
    a: false,
    b: false,
    c: false,
  }
}

This results in a setup like the following:

<WC onChange={e => {
  const selectedKeys = e.target.selectedOptions.map(({value}) => value)
  const updated = Object.keys(this.state.someObj).reduce((obj,key) => ({...obj, [key]:selectedKeys.includes(key)}),{});
  this.setState({someObj: updated})
}}>
  <sp-dropdown placeholder="Make a selection...">
    <sp-menu multiple slot="options">
      {
        Object.keys(this.state.someObj).map(key => {
          return <sp-menu-item selected={this.state.someObj[key] ? true : null} key={key} value={key}>{key}</sp-menu-item>
        })
      }
    </sp-menu>
  </sp-dropdown>
</WC>

However, if your state looks more like that (using arrays)…

const state = {
  options: ["a", "b", "c"],
  selectedOptions: [],
}

… the setup would probably be similar to:

<WC onChange={e => {
  const selectedOptions = e.target.selectedOptions.map(({value}) => value)
  this.setState({selectedOptions})
}}>
  <sp-dropdown placeholder="Make a selection...">
    <sp-menu multiple slot="options">
      {
        this.state.options.map(opt => {
          return <sp-menu-item selected={this.state.selectedOptions.includes(opt) ? true : null} key={opt} value={opt}>{opt}</sp-menu-item>
        })
      }
    </sp-menu>
  </sp-dropdown>
</WC>


So far so good, but there’s still a problem:

The selected property of a sp-menu-item seems to have been designed for non-multiple sp-menus only. It overwrites the current selected value so that there’s always just one selected item at a time, which prevents me from prefilling the dropdown with the initial values.

One more thought:
Maybe the sp-dropdown / sp-menu should expose more events than just a change event? If it provided a more specific onSelect(opt), state updates would be a lot easier as only the single changed option would have to be updated.

Edit: Another thing I just noticed:
When there’s more than one option selected, the dropdown text will only display the first selected options name. From a usability point of view that’s quite problematic as the user has no visual feedback of what’s selected and if his selection worked, other than reopening the dropdown to double-check. Commonly it should show something like “Option1, Option2” or “2 Selected”.

1 Like

Are there any news regarding these 3 points?

Another bug / missing feature for sp-menu: It’s not possible to pre-select multiple sp-menu-items. If more than one element has the selected attribute, only the last one will be selected at the start.
Additional menu items can only be selected via user interaction :confused:

Hi @simonhenke , thank you for noting these bugs with sp-menu and sp-dropdown. I’ll be sure to pass these notes on to the right people. And this answer is late but the forums is a great place to file bugs you notice!

1 Like

Hello everyOne!
is this issue resolved now?
Since I still facing the issue.

I had the same issue; I tried to use a wrapper as described here. But nothing worked. Out of desperation, I tried adding an onClick on the sp-menu-item elements of the sp-picker, and it worked.

Also, if you’re looking to use multiple selection, adding multiple=“true” to sp-menu seems to do the trick. Then, if using react, you can add a useRef onto the sp-menu to find the selected options.

Here’s an example of sp-picker that works for me:

<sp-picker>
  <sp-label slot="label">Pick your option(s)</sp-label>
    <sp-menu ref={pickerRef} multiple="true" >
        {elementsList.map(element => (
            <sp-menu-item key={element} value={element} onClick={handleSelect}>
              {element}
            </sp-menu-item>
        ))}
    </sp-menu>
</sp-picker>

Here’s the handleSelect:

const handleSelect = () => {        
        let selectedOptions = [];
        for (const menuItem of pickerRef.current.selectedOptions) {
            selectedOptions.push(menuItem.value);
        }   
        console.log(selectedOptions)
    };

Don’t forget to add useRef to your react import and declare the ref before using it. I hope this helps.