Styling Bokeh widgets with CSS

I’m trying to apply custom styling to my bokeh widgets. My setup includes a custom html template, to which I add my modules via curdoc().add_root(). I have successfully added css classes to the elements I want to style, but because of the shadow roots bokeh is creating, I can not apply styling to them.

I have tried creating a GlobalInlineStyleSheet and adding that to the first widget I create. The result is that the style element is added to the HTML header, but not to the shadow root, see the example below.

What is the intended way to add styling here? Do I actually need to add the same ImportedStyleSheet / InlineStyleSheet to every widget I create?

stylesheet = GlobalInlineStyleSheet(css = open("static/css/styles.css").read())
self.fileUploader = fileUploader(self.readFile, stylesheet=self.stylesheet)
curdoc().add_root(self.fileUploader.layout)

class fileUploader:
    def __init__(self, callback, name: str = "fileUploader", stylesheet=None):
        self.name = name
        self.stylesheet = stylesheet
        self.fileInput = FileInput(
            name="fileInput", title="Select files:", accept=".xml"
        )
        self.fileInputMessage = Div(
            name="fileInputMessage",
            text="No file uploaded yet!",
            css_classes=["msg-neutral"],
        )
        jsCallback = CustomJS(
            args=dict(div=self.fileInputMessage, file_input=self.fileInput),
            code="""
                div.text = "Processing file…"
                div.css_classes = ["msg-positive"]
            """,
        )
        self.fileInput.js_on_change("filename", jsCallback)
        self.fileInput.on_change("filename", callback)
        self.layout = column(
            children=[self.fileInput, self.fileInputMessage], 
            name=self.name,
            stylesheets = [self.stylesheet]
        )
{% from macros import embed %}
<!DOCTYPE html>
<html lang="en">
  {% block head %}
  <head>
  {% block inner_head %}
    <meta charset="utf-8">
    <title>{% block title %}{{ title | e if title else "Bokeh Plot" }}{% endblock %}</title>
  {%  block preamble -%}{%- endblock %}
  {%  block resources %}
  {%   block css_resources -%}
    {{- bokeh_css if bokeh_css }}
  {%-  endblock css_resources %}
  {%   block js_resources -%}
    {{  bokeh_js if bokeh_js }}
  {%-  endblock js_resources %}
  {%  endblock resources %}
  {%  block postamble %}{% endblock %}
  {% endblock inner_head %}
  </head>
  {% endblock head%}
  {% block body %}
  <body>
    <header>
        <h1>Title</h1>
    </header>
    {%  block inner_body %}
    {%    block contents %}
    <div>
      {{ embed(roots.fileUploader) }}
    </div>
  {%    endblock contents %}
  {{ plot_script | indent(4) }}
  {%  endblock inner_body %}
    <footer>
        <div>Version: 0.1.0</div>
    </footer>
  </body>
  {% endblock body%}
</html>
1 Like

+1 would love to see an example usage somewhere. Duplicate topic here (that I also commented on :joy: ) : How to use GlobalInlineStyleSheet?

I have resorted to InlineStyleSheet on individual widgets :frowning:

I’d suggest that both of you add comments about your usage needs to this PR:

an we may want to open a separate issue around this as well. But what is needed here is a clear step-by-step description of the desired usage/workflow to use as requirements.

I am not sure what the best way to programmatically update CSS from inside a CustomJS is these days, @mateusz may have more suggestions here or in the PR comments.

Thank you, that PR link helped clear some things up for me! I’ll make some suggestions in the PR, here’s where I went wrong:

  • Like you say in the PR, I expected to be able to use the css classes to style elements with a single css file linked from the html. However, I still think css classes are useful (at least for me), I think adding just one or two sentences to the documentation would help.
    • My use case for css classes is as follows: I have a <div> that I use to display messages to the user. Depending on the content, I want to color them differently (red for error messages, green for success etc) and simply changing the css class attached to it seems like the easiest way to me. It’s how I would handle it elsewhere in web apps too.
  • Because of the name, I expected GlobalInlineStyleSheets to be applied globally, to all widgets.
  • I didn’t know I was looking for them, so I didn’t find themes. I have now learned that they do what I expected global style sheets to do.
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.