How include a javascript library in a Bokeh extension


I’m trying to create a bokeh extension by wrapping

The .js library is available here[email protected]/dist/js/tabulator.min.js


My question is where should I import the .js library and why?


As far as I can see I have several options.

  1. __java__script attribute of bokeh python model.
  2. npm install it and import in top of bokeh typescript model
  3. Include it in a script tag like you show in the example.

My guess is that 1. should be the approach.

But if I don’t do 2. then I get errors when I panel build/ bokeh build tabulator in the .ts model.

I have a feeling that 3. is deprecated. But I am not sure.

Preliminary Code


// See
import { HTMLBox, HTMLBoxView } from "@bokehjs/models/layouts/html_box"

// See
import * as p from "@bokehjs/core/properties"

// The view of the Bokeh extension/ HTML element
// Here you can define how to render the model as well as react to model changes or View events.
export class TabulatorView extends HTMLBoxView {
    model: Tabulator
    // objectElement: any // Element

    connect_signals(): void {

        this.connect(, () => {

    render(): void {
        // var table = new Tabulator(this.el, this.model.configuration)
        // this.objectElement.addEventListener("click", () => {this.model.clicks+=1;}, false)

export namespace Tabulator {
    export type Attrs = p.AttrsOf<Props>
    export type Props = HTMLBox.Props & {
        configuration: p.Property<any>,
        data: p.Property<any>
        selected_indicies: p.Property<number[]>

export interface Tabulator extends Tabulator.Attrs { }

// The Bokeh .ts model corresponding to the Bokeh .py model
export class Tabulator extends HTMLBox {
    properties: Tabulator.Props

    constructor(attrs?: Partial<Tabulator.Attrs>) {

    static init_Tabulator(): void {
        this.prototype.default_view = TabulatorView;

            configuration: [p.Any, ],
            data: [p.Any, ],
            selected_indicies: [p.Any, []]

"""Implementation of the Tabulator pane.


from bokeh.core import properties
from bokeh.models import ColumnDataSource
from bokeh.models.layouts import HTMLBox

JS_SRC = "[email protected]/dist/js/tabulator.min.js"
MOMENT_SRC = "[email protected]/moment.js"

    "default": "[email protected]/dist/css/tabulator.min.css",
    "site": "[email protected]/dist/css/site.min.css",
    "simple": "[email protected]/dist/css/tabulator_simple.min.css",
    "midnight": "[email protected]/dist/css/tabulator_midnight.min.css",
    "modern": "[email protected]/dist/css/tabulator_modern.min.css",
    "bootstrap": "[email protected]/dist/css/bootstrap/tabulator_bootstrap.min.css",
    "bootstrap4": "[email protected]/dist/css/bootstrap/tabulator_bootstrap4.min.css",
    "semantic-ui": "[email protected]/dist/css/semantic-ui/tabulator_semantic-ui.min.css",
    "bulma": "[email protected]/dist/css/bulma/tabulator_bulma.min.css",
    "materialize": "[email protected]/dist/css/materialize/tabulator_materialize.min.css",

class Tabulator(HTMLBox):
    """A Bokeh Model that enables easy use of Tabulator tables

    __javascript__ = [
    __css__ = [CSS_HREFS["default"]]

    configuration = properties.Dict(properties.String, properties.Any)
    data = properties.Instance(ColumnDataSource)
    selected_indicies = properties.List(properties.Int)

A bonus question is how to handle that Tabulator is loaded by the .js library. But I would also like to call my Bokeh model Tabulator :slight_smile:

My guess is that the Katex extension example follows best practice

@MarcSkovMadsen I don’t think you have to rely on CDN loads if you don’t want to, AFAIK you can use build to bundle everything together up front. @mateusz is the best person to comment, but you can also refer to the examples here:

1 Like