Styling drop down menus with colour

Hi all,

I just love Input.select. What an amazingly simple API.

I am wondering if there is anyway to style the selections in the dropdown menu? Specifically I am interested in adding colour to the text. So take for example this dropdown menu:

viewof menu = Inputs.select(["one", "two"], {value: "one", label: "Drop down"})

Is there any way to add these colours to the text in the dropdown?

["#20bcd2", "#d3bea6"]

Probably not.

The Input APIs seem to be simple JavaScript wrappers over the basic HTML form elements, and that’s not something you can do with raw HTML at this point.

Here’s a good starting point (with links): <select>: The HTML Select element - HTML: HyperText Markup Language | MDN

Does this help? Is Observable Inputs style-able? / Saneef H. Ansari | Observable

I fairly new with observable but I was hesitant to add the view dependency with that. I was hoping I could accomplish it without that.

1 Like

Looks like it should be possible. I only went so far as re-constructing Saneef’s example, which is not a drop-down selector, but it overall appears to work by just passing in CSS:

A few pointers:

  1. You can style a native select’s options, but only when multiple=true (at least on macOS, other systems might be more lenient).
  2. A viewof element is just a DOM element with a value property. You can tweak it to your heart’s delight before returning it, e.g.:
    viewof menu = {
     const form = Inputs.select(["one", "two"], {value: "one", label: "Drop down", multiple: true});
     form.input.children[0].style.background = "#20bcd2";
     form.input.children[1].style.background = "#d3bea6";
     return form;
    }
    
  3. For most cases you can use Inputs.form() instead of Tom’s view helper.
  4. Other widgets like Inputs.radio() allow you to pass a format callback with which you can wrap your options, e.g.
    viewof menu = Inputs.radio(["one", "two"], {
      value: "one",
      label: "Drop down", multiple: true,
      format: (d, i) => htl.html`<span style=${{
        background: ["#20bcd2", "#d3bea6"][i],
        padding: "0 4px"
      }}>${d}`
    })
    
    

I’m fairly certain that you can even tweak a radios widget to look like a dropdown via selectors like :checked and order. :slight_smile:

1 Like

Hacked-together demo:

2 Likes

This is SO amazing. For my purposes I really don’t want users to be able to select multiple but even just this thread is an absolute treasure. Thank you!

1 Like

I should probably have added that I would not recommend emulating a dropdown this way. Overlays don’t work well in Observable as their visible region is limited to the sandbox iframe and they’ll be covered by any open or pinned editors. This particular implementation is also an accessibility nightmare. :sweat_smile:

Still, you can do quite a lot with radios. See these options for example:


Inputs.table() also lets you use radios if you set its multiple option to false:

viewof penguin = Inputs.table(penguins, {multiple: false})
1 Like