Custom widgets empower you to extend Bokeh’s functionality beyond built-in models by writing small TypeScript/JavaScript components that integrate seamlessly with Python. This guide walks through setting up your development environment, building a widget, packaging it, and deploying to Bokeh server or standalone documents.
1. Set Up Development Environment
- Install prerequisites:
# Python environment pip install bokeh # Node.js and Yarn # Download from https://nodejs.org - Clone Bokeh extension template:
git clone https://github.com/bokeh/sample-custom-extension.git my_widget cd my_widgetThis template includestsconfig.json, webpack setup, and Python bindings. - Install JavaScript dependencies:
cd my_widget yarn install
2. Define Python Wrapper
Create my_widget.py with a subclass of Widget that maps properties to the JS model:
from bokeh.core.properties import Int, String
from bokeh.models import Widget
from bokeh.util.compiler import TypeScript
# Load compiled TS code
ts = TypeScript("my_widget.ts")
class MyWidget(Widget):
__implementation__ = ts
title = String(default="My Widget")
value = Int(default=0)
color = String(default="blue")
Key points:
__implementation__points to the TS file for widget logic.- Define Bokeh
propertiesthat synchronize Python & JS.
3. Implement TypeScript Model
Edit my_widget.ts to define the JS side:
// my_widget.ts
import {WidgetView, Widget} from "models/widgets/widget"
import * as p from "core/properties"
export class MyWidgetView extends WidgetView {
model: MyWidget
private _div: HTMLDivElement
connect_signals(): void {
super.connect_signals()
this.connect(this.model.properties.value.change, () => this.render())
}
render(): void {
if (!this._div) {
this._div = document.createElement("div")
this.el.appendChild(this._div)
}
this._div.textContent = `${this.model.title}: ${this.model.value}`
this._div.style.color = this.model.color
super.render()
}
}
export namespace MyWidget {
export type Attrs = p.AttrsOf
export type Props = Widget.Props & {
title: p.Property
value: p.Property
color: p.Property
}
}
export interface MyWidget extends MyWidget.Attrs {}
export class MyWidget extends Widget {
properties: MyWidget.Props
__view_type__: MyWidgetView
constructor(attrs?: Partial) {
super(attrs)
}
static init_MyWidget(): void {
this.prototype.default_view = MyWidgetView
this.define({
title: [ p.String, "My Widget" ],
value: [ p.Number, 0 ],
color: [ p.String, "blue" ],
})
}
}
MyWidget.init_MyWidget()
“Use
connect_signals()to handle property changes and update the DOM. Define properties ininit_MyWidget()for automatic syncing.”
4. Compile and Build
- Compile TypeScript and bundle:
yarn build - Install Python package in editable mode:
pip install -e .
Watch for build errors in the console; missing imports or mismatched property names are common.
5. Use Custom Widget in Bokeh App
Create a Python script app.py to test your widget:
from bokeh.io import curdoc from my_widget import MyWidget from bokeh.layouts import column from bokeh.models import Slider widget = MyWidget(title="Counter", value=10, color="green") slider = Slider(start=0, end=100, value=10, step=1, title="Adjust Value") # Link slider to widget.value slider.on_change("value", lambda attr, old, new: setattr(widget, "value", new)) curdoc().add_root(column(widget, slider))
Run the app:
bokeh serve app.py --show
6. Package & Distribute
Publish your widget as a Python package and npm module:
- Update
setup.pyandpackage.jsonmetadata. - Upload Python package to PyPI:
twine upload dist/* - Publish JS package to npm:
npm publish
Ensure
__implementation__ references compiled JS once distributed.7. Advanced Techniques
- Custom Events: Use
this.model.trigger_event()andmodel.stream()for real-time interactions. - External Libraries: Integrate D3.js or Leaflet by importing in TS and manipulating DOM.
- Testing: Write unit tests for Python and JS components using
pytestand Jest.
Quick Reference: Files & Commands
| File | Purpose | Command |
|---|---|---|
| my_widget.py | Python wrapper defining properties | — |
| my_widget.ts | TypeScript model & view logic | — |
| package.json | JS dependencies & build scripts | yarn build |
| setup.py | Python packaging | pip install -e . |
| app.py | Demo Bokeh application | bokeh serve app.py |
