Minor Changes
-
Allow
initializeto return an exports object (#974)initializecan now return a plain object to expose a programmatic API for the widget. This API is accessible to parent widgets viahost.getWidget().export default { initialize({ model }) { return { getValue: () => model.get("value"), setValue: (v) => { model.set("value", v); model.save_changes(); }, }; }, render({ model, el }) { /* ... */ }, };
The return type is distinguished by
typeof: functions are treated as cleanup callbacks (existing behavior), objects are treated as exports, andvoidmeans neither. -
Add
signal(AbortSignal) toinitializeandrenderprops for lifecycle cleanup (#974)Both
initializeandrendernow receive anAbortSignalvia thesignalprop. The signal is aborted when the widget is destroyed (or during HMR). This is the preferred way to manage cleanup going forward — it composes with the broader web platform (addEventListener,fetch, child widgets) and avoids the need to manually track teardown logic.The previous callback-based pattern continues to work but is no longer recommended:
// before export default { render({ model, el }) { let handler = () => { /* ... */ }; model.on("change:value", handler); return () => model.off("change:value", handler); }, }; // after export default { render({ model, el, signal }) { let handler = () => { /* ... */ }; model.on("change:value", handler); signal.addEventListener("abort", () => model.off("change:value", handler)); }, };
signalalso works withaddEventListenerandfetchdirectly:export default { render({ model, el, signal }) { el.addEventListener( "click", () => { /* ... */ }, { signal } ); }, };
-
Add
host.getWidgetandhost.getModelfor widget composition (#974)rendernow receives ahostprop with methods to resolve child widgets by reference, enabling one anywidget to render another inside its DOM.export default { async render({ model, el, signal, host }) { let child = await host.getWidget(model.get("slider")); await child.render({ el, signal }); }, };
On the Python side, widget references are serialized as
"anywidget:<model_id>"strings. A newWidgetTraittraitlet validates anywidget-compatible objects, and aWidgettype alias is provided for annotations:import anywidget class Dashboard(anywidget.AnyWidget): _esm = "dashboard.js" slider = anywidget.WidgetTrait().tag(sync=True) Dashboard(slider=Slider())
host.getWidget(ref)returns{ exports, render }whereexportsis the object returned from the child'sinitialize, andrender({ el, signal })mounts the child's view.host.getModel(ref)returns the raw model for lower-level access.