Minimalist Semantic Markup

Welcome Guest
Please Login or Register

If you have registered but not recieved your activation e-mail in a reasonable amount of time, or have issues with using the registration form, please use our Contact Form for assistance. Include both your username and the e-mail you tried to register with.

Author Topic: Need advice on building a custom select  (Read 69 times)


  • Junior Member
  • *
  • Posts: 13
  • Karma: +1/-0
Need advice on building a custom select
« on: 24 Apr 2024, 07:08:30 pm »
A bit of context: I'm currently building (well, sort of built already) my own custom select because native selects suck in terms of custom styling, and also to practice and to see how far can we really take the progressive enhancement idea. The requirements for it are as follows:

  • it will only exist client-side when scripting is enabled, so it should leave no trace in the HTML with JS turned off
  • its UX should match that of the native select as close as possible, both for mouse and keyboard users
  • accessibility: the treatment it gets from assistive tech should match the native select as close as possible
  • it should play well with Constraint Validation API, e.g. reportValidity should correctly focus on it when it's invalid, validation messages by reportValidity should be correctly announced by assistive tech, checkValidity should work
  • it should seamlessly integrate with built-in form submission
  • it can either be constructed client-side from scratch, or can take an existing native select and enhance it while taking all the data it requires from that native select
  • it should require as little extra CSS as possible compared to the native select; by this I mean that the custom select as a whole should behave, from a styling perspective, just as if it was a native select, e.g. it should obviously be inline-block, etc.

For my first attempt, I implemented the following structure (most of the aria attributes omitted for simplicity):

Code: [Select]
<label id="my-label-1">
<span>Label goes here</span><br>
<span class="custom-select">
  <input aria-hidden="true" tabindex="-1">
  <span role="combobox" aria-labelledby="my-label-1"><span>Currently selected option label goes here</span></span>
  <ul role="listbox">
    <li role="option"><span>Option label goes here</span></li>

So when I get static HTML like this:

Code: [Select]
  <span>Label goes here</span><br>
    <option>Option goes here</option>

it's relatively straightforward to enhance it: I can take all the information I need directly from the <select>, create my custom select and substitute <select> with it.

The <label> gives me proper mouse interactions between the label and the input for free (like propagating focus and hover states from label to input), so I don't have to reimplement them in JS.

The input gets positioned right below the combobox and also has opacity set to 0 for good measure, so that it's hidden both for visual users and for assistive tech, but still available for form submissions, and reportValidity will spawn the validation tooltip in the correct place visually. Naturally I stuff the current selection into "input.value" for it to play well with forms. I also listen to "focus" events on this input, so when reportValidity focuses the input I immediately transfer focus to my combobox.

The listbox is hidden in collapsed state and shown in expanded state via screen media CSS.
I've also implemented most of the mouse and keyboard interactions for all this.

However, after a bit of testing (using VoiceOver, as I'm not equipped to test on proper screen readers at the moment), I discovered several issues:

  • even though reportValidity displays the tooltip in the correct place visually, the validation message is not announced, probably because of dicking around with focus
  • since my aria-labelledby points to the ancestor <label>, the announced combobox label also includes the value stored in the input, which leads to duplicate text being announced (surprisingly, the contents of <ul> are not included in the announced text, not sure why?)
  • <ul> is a children of <label> which is not valid HTML, since <label> only wants phrasing content
  • I haven't found a good way to make the collapsed combobox as wide as the widest of its options without resorting to some rather expensive tricks like calculating text width offscreen via canvas

For my second attempt, I managed to solve the first two issues by using the input itself as a role="combobox", styling it appropriately and intercepting keydown events. It also allowed me to drop aria-labelledby since the ancestor <label> now labels the correct element.
However, the third issue still stands. I really don't want to change <label> to a generic <div> wrapper because I would lose a crapload of functionality that I would then need to manually reintroduce with JS.

So how bad is it really if client-side I create a bit of invalid HTML, like a <ul> inside a <label>? Scripting off this all degrades nicely to proper markup without a trace of this blasphemy, and scripting on... Why would anyone care to validate HTML created from the scripting anyway?

Would love to hear your thoughts about this solution, Jason.

Jason Knight

  • Administrator
  • Hero Member
  • *****
  • Posts: 1060
  • Karma: +188/-1
    • CutCodeDown -- Minimalist Semantic Markup
Re: Need advice on building a custom select
« Reply #1 on: 25 Apr 2024, 11:46:05 am »
My take on it is that if you don't like how the default select works, don't use them. Generally speaking a "select" of more than three options is inaccessible trash anyways, so F*** the whole dropdown mechanism and the source it code in on.

Either live with a nice big fieldset of radio buttons, live with the default appearance, or find some other way to get the user to type information in.

Of course as an accessibility consultant I would tell you to rip out every single select, anything faking the behavior of select, and kick the inner art {expletive omitted} in the groin with their "wah wah eye dunz like teh uppearants" BS.

In case you couldn't guess, not a fan. Same reason I've killed off using dropdown menus on any new sites I build. Only reason this forum has dropdown menus is I've been too lazy to do a new skin from scratch.
We are all, we are all, we are all FRIENDS! For today we're all brothers, tonight we're all friends. Our moment of peace in a war that never ends.


  • Junior Member
  • *
  • Posts: 13
  • Karma: +1/-0
Re: Need advice on building a custom select
« Reply #2 on: 25 Apr 2024, 01:28:10 pm »
Ok, I was kinda expecting this reply. But more to the original point: how bad is it really to generate something like

Code: [Select]

client-side? I know that this is invalid HTML, but what does that even mean for markup generating via scripting? Would some assistive tech break because of this markup? Do I risk encountering incorrect weird browser behaviour?


SMF spam blocked by CleanTalk