Jupyter: How to change color for widgets like SelectMultiple()?

The short answer is: You can't do that without creating your own "custom widget". Those attributes of style and layout objects are hard-coded in both the server-side and client-side libraries of ipywidgets.

There is a dirty way to get a similar effect though, by mixing the ButtonStyle with SelectMultiple.

# Tested on JupyterLab 0.35.3 with Python 3.6 kernel
import ipywidgets as widgets
from ipywidgets.widgets import widget_serialization, trait_types

from traitlets import Unicode, Instance, CaselessStrEnum

class MySelectMultiple(widgets.SelectMultiple):
    style=trait_types.InstanceDict(widgets.ButtonStyle).tag(sync=True, **widget_serialization)

wdg2 = MySelectMultiple(
    options=['Apples', 'Oranges', 'Pears'],
    value=['Oranges'],
    description='Fruits',
    layout=widgets.Layout(width='75%', height='80px'),
    style= {'button_color':'red'},
    disabled=False
)

wdg2

wdg2_red

wdg2.style.button_color = 'green'

wdg2_green

Another dirty way is to inject a CSS rule into the notebook which affects all select widget.

%%html
<style>
    .widget-select > select {background-color: red;}   
</style>

enter image description here

Custom widget

The ultimate solution is to make your own custom widget. Unfortunately you need to write both server- and client side codes for it. For classical jupyter notebook, the client side code (JavaScript) can be put in a cell. But this feature may be dropped in the "next-generation" of Jupyter, i.e. JupyterLab, for security reasons.

Cell 1

%%javascript
require.undef('myselectmultiple');
define('myselectmultiple', ["@jupyter-widgets/base"], function(widgets) {
    class selectmultipleView extends widgets.SelectMultipleView {
        render () {
            super.render();
            this.mycolor_changed();
            this.model.on('change:mycolor', this.mycolor_changed, this);
        }
        mycolor_changed () {
            var mycolor = this.model.get('mycolor')
            this.el.childNodes[1].style.backgroundColor = mycolor;
        }
    }
    return {
        myselectmultipleview : selectmultipleView
    };
});

Cell 2

class MySelectMultipleC(widgets.SelectMultiple):
    _view_name = Unicode('myselectmultipleview').tag(sync=True)
    _view_module = Unicode('myselectmultiple').tag(sync=True)
    _view_module_version = Unicode('0.1.0').tag(sync=True)
    mycolor = Unicode('white', help='background color').tag(sync=True)

wdg3 = MySelectMultipleC(
    options=['Apples', 'Oranges', 'Pears'],
    value=['Oranges'],
    description='Fruits',
    mycolor = 'green',
    disabled=False
)
wdg3

enter image description here

Cell 3

wdg3.mycolor = 'red'

enter image description here

JupyterLab uses a completely different framework. To make the above custom widget working in the "Lab" interface, the client-side code should be translated to TypeScript, and then be compiled, built and installed on the Lab server.


Late to the party, but here is my simple solution, for the case where the color will be used to encode simple two (or a number of) states: use unicode!

sample:

enter image description here

code (in python 3... :) )

from ipywidgets import interactive, Layout
from IPython.display import clear_output
import ipywidgets as widgets
from IPython.display import display

c_base = int("1F534",base=16)
# widget 1
options=['Apples', 'Oranges', 'Pears']
state = [False,True,True]
colored_options = ['{} {}'.format(chr(c_base+s), o) for s,o in zip(state,options)]
wdg = widgets.SelectMultiple(
    options=colored_options,
    description='Fruits',
    disabled=False
)

display(wdg)

Try searching with this code if you need more colours...:

for i in range (10):
    ii = int('0x1f7e0',base=16)+i
    print('{:>15}'.format('[{}: {}] '.format(hex(ii),chr(ii))),end='')
    if i%7==6:
        print()

enter image description here