Custom CSS Style

I’m having trouble figuring out how to assign my custom css styles to my widgets. Based on such posts as Embedded css - is there any equivalent for the below implementation of css into Bokeh?, I’m setting up my Bokeh server using the directory format model. However, I don’t see any examples in which custom CSS is used for individual widgets. The GapMinder (bokeh/examples/app/gapminder at branch-2.4 · bokeh/bokeh · GitHub) and Faces (bokeh/examples/app/faces at branch-2.4 · bokeh/bokeh · GitHub) examples use the directory format for custom CSS, but those styles apply to the entire document as opposed to individual widgets.

Let’s say I want to mimic the Sliders example (bokeh/sliders.py at branch-2.4 · bokeh/bokeh · GitHub), but I want to put a border around the column of 5 widgets on the list.

I’d take sliders.py and put in a sliders directory with the name main.py, and modify line 72 to be:

inputs = column(children=[text, offset, amplitude, phase, freq], css_classes=['foo'])

In sliders/templates/index.html, I have:

{% extends base %}

{% block contents %}
  <link rel="stylesheet" href="sliders/static/css/styles.css" />
  {{ super() }}
{% endblock %}

In sliders/static/css/styles.css, I have:

foo {
        border: 5px
}

Then, from the directory above sliders, I run: bokeh serve sliders. This does not result in a border around the column of widgets. The column of widgets does indeed show class="bk foo" in the inspector, but border is set to 0.

What am I doing wrong?

Have you checked the browser network pane to see whether the CSS file is actually loading successfully or not? If not, what is the error? In any case, to speculate further I’d really need a complete Minimal Reproducible Example that could actually be run and investigated.

There’s no error; the web page just doesn’t show a border.
I see styles.css in the Sources section of Inspector in Chrome, so I think it loaded correctly.

I think I included a MPE, no? All the files that need to be present were included…I guess I could add that I’m running Python 3.8.5 with Bokeh 2.2.3 and viewing the webpage in Chrome 91.0.4472.114 on a Mac running Catalina 10.15.7.

Perhaps I didn’t make it clear enough that my main.py is an exact copy of bokeh/sliders.py at branch-2.4 · bokeh/bokeh · GitHub, with only the single line I mentioned having been changed. Not so sure what else I’d need to include?

Perhaps I can ask alternatively…

What is the method by which one can assign custom css styles to widgets using a custom Jinja template? The css_classes method looks like it should be the answer, but the method by which one should define the css class referred to is unclear.

I searched github for css_classes, and the only example which uses it is bokeh/css_classes.py at ed54705d627ae500509e57fe071fc7a60fc8a951 · bokeh/bokeh · GitHub, which defines the css class in a Div widget placed on the page. Otherwise I don’t see any documentation for how to use css_classes.

Otherwise I don’t see any documentation for how to use css_classes .

css_classes is documented in the reference guide, there is an entry for every model, e.g. bokeh.models.layouts — Bokeh 2.3.3 Documentation There is not much to say:

A list of CSS class names to add to this DOM element.

Any value(s) you set the property to will be added to a DOM element for the widget or layout. As for what the class does, that is up to you to define in a stylesheet. Your code seems OK at a quick glance, which is why it will have to be run to be investigated.

I think I included a MPE, no?

Ish. If I can literally copy/paste text into a single file and run it, no changes, then I will typically do so right away and see if there is an obvious, immediate answer. Or likewise a single git clone. Anything beyond that will typically be deferred until a weekend when I actually have time to tinker with things.

Fair enough. Here’s a git repo with the example that can be simply cloned: GitHub - EfremBraun/sliders-example

A few things were immediately evident on actually running code. The current stylesheet is loading under <body> but it is probably better to load it in <head> with the rest of the CSS resources:

{% block css_resources %}
  <link rel="stylesheet" href="/sliders-example/static/css/styles.css" />
  {{ super() }}
{% endblock %

Also note I had to change the link to /sliders-example to accommodate the actual name of the app.

More importantly, the CSS selector was not targetting a class. It should be .foo not foo. Also I should be very up front that state that Bokeh tries to completely manage the layout of things inside its own containers like row, so tinkering with things that affect layout is not necessarily going to work well. E.g. I had to add !important to get the browser to supercede Bokeh’s own settings:

.foo {
    border: 5px solid red !important;
}

But even then, as mentioned, these layout related settings conflict with Bokeh and the result is not great:

If you want to control things at this level you will need to template individual items as separate document roots in the template by name, rather than putting all the items inside Bokeh-managed containers like row. See e.g. Running a Bokeh server — Bokeh 2.3.3 Documentation. Then you can freely customize whatever (non-Bokeh) DOM element contains the individual items inside.