Widgets and comms reference
The widget model that jupyter.widget(options) returns, and the comm API under jupyter.comm, with their arguments, return values and an example. Widgets and comms explains them with a full walk-through, including the view module. Examples that can run on their own show the output they produced; widgets run on the page.
Overview
A widget is an anywidget model: state that the kernel and its views share, and a view module that draws it. Use one for interactive output: controls, progress, a chart that updates.
A comm is the channel widgets are built on: messages both ways on a target name, with no shared state and no view. Use one to talk to a frontend extension that registered a target.
| Member | What it does |
|---|---|
widget.get(key) | The current value of a state key. |
widget.set(key, value) | Change one state key, or several at once, and sync the change to every view. |
widget.fullState() | The full state, as the frontend sees it: anywidget's model keys (_model_name, _view_name and the rest) and the widget's own. |
widget.on(event, listener) | Listen for state changes or custom messages from the views. |
widget.off(event, listener) | Remove a listener added with on. |
widget.send(content, buffers?) | Send a custom message to every view's model.on("msg:custom", ...). |
widget.close() | Close the model. |
| Member | What it does |
|---|---|
jupyter.comm.open(targetName, data?, options?) | Open a comm to a target the frontend registered. |
jupyter.comm.registerTarget(targetName, handler) | Accept comms the frontend opens on targetName. |
jupyter.comm.unregisterTarget(targetName) | Stop accepting new comms on targetName. |
comm.send(data?, options?) | Send a message to the frontend's end. |
comm.close(data?, options?) | Close the comm and tell the frontend. |
comm.onMsg(handler) | Handle messages from the frontend's end. |
comm.onClose(handler) | Handle the comm closing, from either end. |
Widget model
An anywidget model, from jupyter.widget, synced with its frontend views. Display it to show a view; display it again for a second view of the same model.
jupyter.widget(options) returns it; see the jupyter reference.
State
The synced state, read and changed from the kernel.
widget.get(key)
get(key: string): unknown;The current value of a state key.
| Parameter | Type | Required | Description |
|---|---|---|---|
key | string | yes | The state key. |
Returns unknown: Its value, or undefined.
const w = jupyter.widget({ esm: "export default {}", state: { count: 0 } });
w.get("count"); // 00widget.set(key, value)
set(key: string, value: unknown): void;
set(changes: WidgetState): void;Change one state key, or several at once, and sync the change to every view. Fires this model's own change listeners too. After close it changes the local state only.
| Parameter | Type | Required | Description |
|---|---|---|---|
key | string | no | The state key. |
value | unknown | no | Its new value. |
changes | WidgetState | no | Several keys and their new values, instead of key and value. |
const w = jupyter.widget({ esm: "export default {}", state: { count: 0, label: "" } });
w.set("count", 1);
w.set({ count: 2, label: "two" });const progress = jupyter.widget({
esm: `export default {
render({ model, el }) {
el.innerHTML =
'<div class="progress-track"><div class="progress-fill"></div></div>' +
'<div class="progress-label"></div>';
const fill = el.querySelector(".progress-fill");
const label = el.querySelector(".progress-label");
const update = () => {
const percent = Math.round(model.get("value") * 100);
fill.style.width = percent + "%";
label.textContent = model.get("message") + " (" + percent + "%)";
};
model.on("change:value", update);
model.on("change:message", update);
update();
},
};`,
css: `
.progress-track { width: 320px; height: 10px; border-radius: 5px; background: #e5e7eb; overflow: hidden; }
.progress-fill { height: 100%; background: #2e6e64; transition: width 0.2s; }
.progress-label { margin-top: 6px; font: 13px system-ui, sans-serif; color: #444; }
`,
state: { value: 0, message: "Starting" },
});
await jupyter.display(progress);
const files = ["january.csv", "february.csv", "march.csv", "april.csv", "may.csv"];
for (const [i, file] of files.entries()) {
progress.set({ message: "Processing " + file, value: i / files.length });
await new Promise((resolve) => setTimeout(resolve, 600)); // stand-in for real work
}
progress.set({ message: "Done", value: 1 });Running from the saved notebook, with no kernel behind this page.
widget.fullState()
fullState(): WidgetState;The full state, as the frontend sees it: anywidget's model keys (_model_name, _view_name and the rest) and the widget's own.
Returns WidgetState: Every state key and its value.
const w = jupyter.widget({ esm: "export default {}", state: { count: 0 } });
w.fullState(); // { _model_name: "AnyModel", _model_module: "anywidget", ..., count: 0 }{
_model_name: 'AnyModel',
_model_module: 'anywidget',
_model_module_version: '*',
_view_name: 'AnyView',
_view_module: 'anywidget',
_view_module_version: '*',
_view_count: null,
_esm: 'export default {}',
_anywidget_id: 'cdp-kernel.widget',
count: 0
}Events
State changes and custom messages from the views.
widget.on(event, listener)
on(event: `change:${string}`, listener: (value: unknown, previous: unknown) => void | Promise<void>): void;
on(event: "change", listener: (changes: WidgetState) => void | Promise<void>): void;
on(event: "msg:custom", listener: (content: unknown, buffers: Uint8Array[]) => void | Promise<void>): void;Listen for state changes or custom messages from the views. change:key gets the new and previous value; change gets all the changed keys; msg:custom gets a view's model.send content.
| Parameter | Type | Required | Description |
|---|---|---|---|
event | depends on the overload: see the signatures | yes | change:<key>, change or msg:custom. |
listener | depends on the overload: see the signatures | yes | Called for each event; may be async. |
const w = jupyter.widget({ esm: "export default {}", state: { count: 0 } });
w.on("change:count", (value, previous) => console.log(previous, "->", value));
w.on("msg:custom", (content) => console.log("view sent", content));const temperature = jupyter.widget({
esm: `export default {
render({ model, el }) {
const slider = document.createElement("input");
slider.type = "range";
slider.min = "-20";
slider.max = "40";
const label = document.createElement("span");
const update = () => {
slider.value = String(model.get("celsius"));
label.textContent = " " + model.get("celsius") + " °C is " + model.get("fahrenheit") + " °F";
};
slider.oninput = () => {
model.set("celsius", slider.valueAsNumber);
model.save_changes();
};
model.on("change:celsius", update);
model.on("change:fahrenheit", update);
update();
el.append(slider, label);
},
};`,
state: { celsius: 20, fahrenheit: 68 },
});
temperature.on("change:celsius", (celsius) => {
temperature.set("fahrenheit", Math.round((Number(celsius) * 9) / 5 + 32));
});
temperature;As the kernel left it after the docs build sent a slider move to 30 from the view. Running from the saved notebook, with no kernel behind this page.
widget.off(event, listener)
off(event: string, listener: (...args: never[]) => unknown): void;Remove a listener added with on.
| Parameter | Type | Required | Description |
|---|---|---|---|
event | string | yes | The event it was added for. |
listener | (...args: never[]) => unknown | yes | The same function. |
const w = jupyter.widget({ esm: "export default {}", state: { count: 0 } });
const log = (value: unknown) => console.log(value);
w.on("change:count", log);
w.off("change:count", log);Custom messages
Messages to the views that aren't state; on("msg:custom", ...) receives theirs.
widget.send(content, buffers?)
send(content: unknown, buffers?: Uint8Array[]): void;Send a custom message to every view's model.on("msg:custom", ...).
| Parameter | Type | Required | Description |
|---|---|---|---|
content | unknown | yes | JSON content. |
buffers | Uint8Array[] | no | Binary buffers. Default []. |
const w = jupyter.widget({ esm: "export default {}" });
w.send({ type: "reset" });const dice = jupyter.widget({
esm: `export default {
render({ model, el }) {
const button = document.createElement("button");
button.textContent = "Roll 3 dice";
button.onclick = () => model.send({ count: 3 });
const result = document.createElement("span");
result.style.marginLeft = "12px";
result.style.fontSize = "24px";
model.on("msg:custom", (message) => {
result.textContent = message.faces + " (total " + message.total + ")";
});
el.append(button, result);
},
};`,
});
dice.on("msg:custom", (content) => {
const { count } = content as { count: number };
const rolls = Array.from({ length: count }, () => 1 + Math.floor(Math.random() * 6));
dice.send({
faces: rolls.map((n) => "⚀⚁⚂⚃⚄⚅"[n - 1]).join(" "),
total: rolls.reduce((a, b) => a + b, 0),
});
});
dice;As the kernel left it after the docs build sent a click from the view. Running from the saved notebook, with no kernel behind this page.
Closing
widget.close()
close(): void;Close the model. Its views stop syncing.
const w = jupyter.widget({ esm: "export default {}" });
w.close();Properties
| Property | Type | Description |
|---|---|---|
id | string | The model id (the comm id). |
closed | boolean | Whether the model has been closed. |
Comms
jupyter.comm opens comms and accepts the ones the frontend opens; each is a Comm object.
jupyter.comm
jupyter.comm: open comms, and accept comms the frontend opens.
jupyter.comm.open(targetName, data?, options?)
open(targetName: string, data?: { [key: string]: unknown }, options?: CommSendOptions): Comm;Open a comm to a target the frontend registered.
| Parameter | Type | Required | Description |
|---|---|---|---|
targetName | string | yes | The frontend's target name. |
data | { [key: string]: unknown } | no | Data sent with the open message. Default {}. |
options | CommSendOptions | no | Metadata and binary buffers. |
Returns Comm: The kernel's end of the comm.
const comm = jupyter.comm.open("my.target", { hello: 1 });
comm.onMsg((m) => console.log(m.data));jupyter.comm.registerTarget(targetName, handler)
registerTarget(targetName: string, handler: (comm: Comm, msg: CommMessage) => void | Promise<void>): void;Accept comms the frontend opens on targetName. Registering the same name again replaces the handler.
| Parameter | Type | Required | Description |
|---|---|---|---|
targetName | string | yes | The target name the frontend opens comms on. |
handler | (comm: Comm, msg: CommMessage) => void | Promise<void> | yes | Called with the new comm and its open message. |
jupyter.comm.registerTarget("echo", (comm) => comm.onMsg((m) => comm.send(m.data)));jupyter.comm.unregisterTarget(targetName)
unregisterTarget(targetName: string): void;Stop accepting new comms on targetName. Comms already open stay open.
| Parameter | Type | Required | Description |
|---|---|---|---|
targetName | string | yes | The target to remove. |
jupyter.comm.unregisterTarget("echo");Comm object
One end of a Jupyter comm channel, from jupyter.comm.open or a target handler.
comm.send(data?, options?)
send(data?: { [key: string]: unknown }, options?: CommSendOptions): void;Send a message to the frontend's end. Does nothing once closed.
| Parameter | Type | Required | Description |
|---|---|---|---|
data | { [key: string]: unknown } | no | The message's JSON data. Default {}. |
options | CommSendOptions | no | Metadata and binary buffers. |
const comm = jupyter.comm.open("my.target");
comm.send({ ping: true }, { buffers: [new Uint8Array([1, 2, 3])] });comm.close(data?, options?)
close(data?: { [key: string]: unknown }, options?: CommSendOptions): void;Close the comm and tell the frontend. Its onClose handlers start right away, without being awaited. Does nothing once closed.
| Parameter | Type | Required | Description |
|---|---|---|---|
data | { [key: string]: unknown } | no | Data sent with the close message. Default {}. |
options | CommSendOptions | no | Metadata and binary buffers. |
const comm = jupyter.comm.open("my.target");
comm.close({ reason: "done" });comm.onMsg(handler)
onMsg(handler: (msg: CommMessage) => void | Promise<void>): void;Handle messages from the frontend's end. A handler runs like a cell: its output goes to the notebook, and an exception shows on stderr.
| Parameter | Type | Required | Description |
|---|---|---|---|
handler | (msg: CommMessage) => void | Promise<void> | yes | Called with each message; may be async. |
const comm = jupyter.comm.open("my.target");
comm.onMsg(({ data, buffers }) => console.log(data, buffers.length));comm.onClose(handler)
onClose(handler: (msg: CommMessage) => void | Promise<void>): void;Handle the comm closing, from either end.
| Parameter | Type | Required | Description |
|---|---|---|---|
handler | (msg: CommMessage) => void | Promise<void> | yes | Called with the close message; may be async. |
const comm = jupyter.comm.open("my.target");
comm.onClose(() => console.log("closed"));Properties
| Property | Type | Description |
|---|---|---|
id | string | The comm id, shared with the frontend's end. |
targetName | string | The target the comm was opened on. |
closed | boolean | Whether either end has closed the comm. |
Types
WidgetOptions
Options for jupyter.widget.
| Property | Type | Required | Description |
|---|---|---|---|
esm | string | yes | The anywidget view module, as source: export default { render({ model, el }) { ... } }. A ${...} inside a template literal here is filled in by the kernel, not the browser: escape it as \${...}. |
css | string | no | CSS for the view. |
state | WidgetState | no | The initial synced state. Uint8Array and ArrayBuffer values travel as binary buffers. Default {}. |
CommMessage
A comm message as a handler receives it.
| Property | Type | Required | Description |
|---|---|---|---|
data | { [key: string]: unknown } | yes | The message's JSON data. |
metadata | { [key: string]: unknown } | yes | The message's metadata. |
buffers | Uint8Array[] | yes | Binary buffers sent with the message. |
CommSendOptions
Options for sending, opening or closing a comm.
| Property | Type | Required | Description |
|---|---|---|---|
metadata | { [key: string]: unknown } | no | Metadata for the message. Default {}. |
buffers | Uint8Array[] | no | Binary buffers sent with the message. Default []. |