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_widget
This 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
properties
that 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.AttrsOfexport 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.py
andpackage.json
metadata. - 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
pytest
and 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 |