whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.16k stars 2.69k forks source link

Allow adding icons/images to <select> and <datalist> <option>s #3596

Open alekseyg opened 6 years ago

alekseyg commented 6 years ago

Very often, it is necessary to include icons or images with a list of options. I prefer to use native controls for a variety of reasons, including accessibility, mobile form flow, the fact that <select> boxes can extend outside of their frame or window while being positioned according to the user's OS's rules, etc. However, some options presented to users may that of an icon or a color, where naming the option simply does not communicate the value quite like an image would. In such a case, developers are often forced to use custom form elements which have accessibility and other issues. One possible workaround is to use radio buttons, but when you have perhaps 20 or 30 choices, that can be rather unwieldy. Native OS menus have support for icons, and while the <select> element is essentially a replaced element by a native OS menu, it definitely is a very limited version of it. I will attach some screenshots to illustrate some use cases from an app I recently built.

Use cases: 1) A limited selection of colors. In such a case, simply listing the words is not sufficient, as shades of said colors are important to the user. screen shot 2018-03-27 at 10 26 56 pm

2) A selection of icons. Here it's even more important to have illustrations, as people may imagine a variety of icons for any particular word. Seeing said icon is important in making the decision. screen shot 2018-03-27 at 10 27 18 pm

3) Displaying logos of brands/companies/organizations. This is of course more of a nice to have, since the names of said brands already evoke an image in users' minds, but it comes free with implementing this feature.

I've wanted to propose this feature for a while now, as @wycats suggested I do on Twitter, but I'm only getting around to it now. Here's the thread where it was mentioned: https://twitter.com/wycats/status/945714039631446016

As for possible solutions, perhaps adding an icon attribute to the <option> element or allowing an <img>, <svg>, etc. inside might work. A somewhat less desirable, but still usable solution might be to allow styling <option> elements as suggested in https://github.com/w3c/csswg-drafts/issues/2013 and use ::before pseudo-elements to inject said icons. I would prefer a way where the OS would be able to render the icons at a consistent size and — for icons that don't need to use colors — color, as they are rendered in native OS menus, but I'm getting ahead of myself.

alekseyg commented 6 years ago

@guest271314 A custom "select" element is exactly the workaround I currently use. The idea is to get browser vendors on board with making the native element more useful so we can retain all the accessibility features of the native element, along with the extra nice things.

guest271314 commented 6 years ago

@alekseyg FWIW, This is the closest have been able to achieve so far to the requirement of using <select> and <option> elements, utilizing <label> elements with for attribute and <input type="button"> elements. The issue with the current approach is that the <input type="button"> elements need to be clicked twice for the expected effect of selecting the <option> and setting <label> elements' display to "none" when the associated <select> element has focus

<!DOCTYPE html>
<html>
<head>
  <style>
    label[for="colors"] input[type="button"] {
      display: inline-block;
      color: transparent;
      width: 50px;
      display: inline-block;
    }
    select {
      position: absolute;
      top: 7px;
      left: 60px;
    }
  </style>
</head>

<body>
  <form>
    <label for="colors" title="red">
      <input type="button" value="red" autofocus/>
    </label>
    <br>
    <label for="colors" title="green">
      <input type="button" value="green" />
    </label>
    <br>
    <label for="colors" title="gold">
      <input type="button" value="gold" />
    </label>
    <select id="colors" label="Colors" value="">
      <option value="" label="select a color" selected disabled></option>
      <option value="red">red</option>
      <option value="green">green</option>
      <option value="gold">gold</option>
    </select>
  </form>
  <script>
    const select = document.querySelector("select");

    const labels = select.labels;

    const options = select.options;

    labels.forEach((label, index) => {
      const button = label.querySelector("input[type=button]");
      button.style.backgroundColor = label.title;
      label.onclick = e => {
        console.log(e.target);
        let {
          value
        } = button;
        let selected = [...options].find(({
          value: val
        }) => value === val);
        [...options].forEach(option => option.removeAttribute("selected"));
        selected.selected = true;
        select.value = selected.value;
        labels.forEach(label => {
          label.style.display = "none";
        });
      }
    });

    select.onfocus = e => {
      console.log(e.type);
      labels.forEach(label => {
        label.style.display = "inline-block";
      });
    };

    select.onchange = e => {
      console.log(e);
      labels.forEach(label => {
        label.style.display = "none";
      });
    };

    select.onblur = e => {
      console.log(e.type);
    };

    select.onclick = e => {
      console.log(e.type);
    }
  </script>
</body>
</html>
JDFlynn1985 commented 6 years ago

I would say that you could do that a lot easier using CSS ID tags rather than JavaScript due to browser and screen reader issues that could come from javaScript where the user could not see the script and CSS also allows for easier implementation

alekseyg commented 6 years ago

Ultimately, the idea behind this issue is that the workarounds will be rendered unnecessary and the limitations thereof will no longer be a problem.

MatsPalmgren commented 6 years ago

I don't see a problem with supporting arbitrary content inside <option>. Firefox did support that in the past IIRC, but we removed it since it wasn't web-compatible. I personally would like to add it back in some form, but we can't do that unless other UAs agree to implement it.

alekseyg commented 6 years ago

Yeah, getting UAs to consider the feature is why I made the issue. Is there anything else I might want to do to bring the idea to the attention of UA devs?

MatsPalmgren commented 6 years ago

You could ask for a comment on the blink-dev list I suppose.

annevk commented 6 years ago

@alekseyg are there bugs filed against all browsers? If so, linking them from here would be nice.

alekseyg commented 6 years ago

I was going to create a message on blink-dev and forgot to, but I went ahead and opened bugs for Blink, Firefox, Edge, and WebKit. Should I do any others and should I also still create a message on blink-dev as well?

https://bugs.chromium.org/p/chromium/issues/detail?id=869480 https://bugzilla.mozilla.org/show_bug.cgi?id=1479854 https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/18470126/ https://bugs.webkit.org/show_bug.cgi?id=188200

tkent-google commented 6 years ago

The proposal is almost same as <menuitem>, which we removed from the specification. Blink team's stance is that we should not provide complex UI features, and should provide primitives to help implementing such UI features instead.

alekseyg commented 6 years ago

@tkent-google Technically, the primitive is already there, but it doesn't render anything other than plain text no matter what HTML you might insert into it. The proposal is just asking to make <option> act a bit more like <button>, into which you can put whatever HTML you wish and have it render. At least, that's one of the options and probably the simplest one.

If you consider the feature unnecessary though, would the ideal alternative be a stylized list of <input type="radio"> elements or is there something better? Also, what's the best way to make such a solution work nicely with mobile forms (e.g. tabbing between fields in iOS)?

The reason I proposed this feature is because custom form controls generally leave a lot to be desired in terms of accessibility and multi-device support over native controls. The solution would then either be to enhance native controls or to enable custom controls to do things they currently can't. If the latter is the way to go, how do we go about proposing that?

acicali commented 3 years ago

The proposal is almost same as <menuitem>, which we removed from the specification. Blink team's stance is that we should not provide complex UI features, and should provide primitives to help implementing such UI features instead.

I believe that allowing arbitrary HTML within <option> elements (both for <select> and <datalist>) would be inline with the goal of providing "primitives to help implementing such UI features". The alternative at this time is a custom form control, which is generally harmful for the web.

tophf commented 3 years ago

Blink team's stance

Judging by the source code, Blink has been using native OS implementation of select's dropdown menu in various OS for a long time, which was the technical reason why it couldn't accept any complex html in the past and probably nudged the team into supporting the restriction on the content in general...