The custom CSS by department 1.7, ready to be used with bokeh applications.
How to style Bokeh Apps with CSS
This file discusses multiple ways to add custom CSS to a bokeh app, as well as helpful hints for writing the CSS file. This Repo contains a small example of how we add our CSS to our bokeh apps.
This note is based on bokeh-3.3.1
.
Getting started with CSS
If you are not familiar with CSS, I recommend the following links to get started:
Adding CSS to Bokeh
There are multiple ways to add CSS styling to Bokeh:
-
Using one or more
InlineStyleSheet
s and/orImportedStyleSheet
s to add styling to a single bokeh element. This way, the style is only added to that specific element, and it appears as a<style>
-block or a<link rel="stylesheet">
in that element's html. If the element contains more elements, it is only attached to the outermost element - see nr 3 for working with shadow roots. For example:from bokeh.models import Div, InlineStyleSheet, ImportedStyleSheet from bokeh.plotting import curdoc stylesheet1 = ImportedStyleSheet(url = "https://cdn.simplecss.org/simple.min.css") stylesheet2 = InlineStyleSheet(css = 'div {color: red}') placeholderDiv = Div(text="This is the styled div", stylesheets=[stylesheet1, stylesheet2]) curdoc().add_root(placeholderDiv)
The resulting HTML looks something like this:
<html lang="en"> <head> ... </head> <body> <div ...> <div class="bk-Div"> <link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css"> <style type="text/css">div {color: red}</style> <div class="bk-clearfix" style="display: inline-block;">This is the styled div</div> </div> </div> </body></html>
-
Similarly to 1., adding style sheets to the root of the document is done by using one or more
GlobalInlineStyleSheet
s and/orGlobalImportedStyleSheet
s. To apply them, they are attached as style sheets to any bokeh element. If you are using custom templates, adding your style sheets to the head will have the same effect. Note that they are only added in the document's<head>
and as such have no effect on any bokeh element inside shadow roots. An Example:from bokeh.models import Div, GlobalInlineStyleSheet, GlobalImportedStyleSheet from bokeh.plotting import curdoc globalStylesheet1 = GlobalImportedStyleSheet(url = "https://cdn.simplecss.org/simple.min.css") globalStylesheet2 = GlobalInlineStyleSheet(css = 'div {color: red}') placeholderDiv = Div(text="This is a div", stylesheets=[globalStylesheet1, globalStylesheet2]) curdoc().add_root(placeholderDiv)
The resulting HTML should look something like this:
<html lang="en"> <head> <meta charset="utf-8"> <title>Bokeh Application</title> <link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css"> <style type="text/css">div {color: red}</style> </head> <body> <div ...> <div class="bk-Div"> This is a div </div> </div> </body> </html>
Note that there is a bug in
bokeh-3.3.1
that preventsGlobalImportedStyleSheet
s from working. It has been fixed and will be included in the next release.Since bokeh places a lot of elements in shadow roots, the styling in the
<head>
will not apply to them. GlobalStyleSheets are still useful to style the overall page appearance, such as side margins. -
If you want to add style sheets to all parts of the app,
Theme
s are what you are looking for. Style sheets added via a theme are added to both the document's head and to every shadow root that bokeh creates, and as such are applied to every element. An example:from bokeh.models import InlineStyleSheet, ImportedStyleSheet from bokeh.plotting import curdoc stylesheet1 = ImportedStyleSheet(url = "https://cdn.simplecss.org/simple.min.css") stylesheet2 = InlineStyleSheet(css = 'div {color: red}') theme = Theme(json=dict(attrs=dict(UIElement=dict(stylesheets=[stylesheet1, stylesheet2]),),),) curdoc().theme = theme
Problems I ran into
While trying to style our bokeh app, I encountered a number of problems.
- Bokeh wraps a lot of it's elements in shadow roots, so that you don't style them accidentally. That can get in the way when trying to style them on purpose. To circumvent that, I used themes.
- Unfortunately, while you are able to pass a
name
to each bokeh element, it is only used in the backend and not added as anid
in the frontend, making it hard to reference elements. - Many elements are wrapped in multiple layers of
div
s, it's helpful to keep that in mind when writing CSS selectors. - bokeh does use it's own classes that correspond to the bokeh widget type of an element, and I highly recommend using the browser's inspector to learn about those when trying to style a particular type of bokeh widget.
All in all, support for custom styling is still under development, so be sure to watch out for any changes that might happen.