Build a Counter Widget
!pip install --quiet anywidget
This example demonstrates how to synchronize model state between the widget frontend and Python kernel with anywidget.
The render
function creates a <button>
element and registers an event handler to increment the model value
when the button is clicked. A second event handler is registered to update the text output each time value
changes on the model.
import anywidget
import traitlets
class CounterWidget(anywidget.AnyWidget):
_esm = """
function render({ model, el }) {
let count = () => model.get("value");
let btn = document.createElement("button");
btn.classList.add("counter-button");
btn.innerHTML = `count is ${count()}`;
btn.addEventListener("click", () => {
model.set("value", count() + 1);
model.save_changes();
});
model.on("change:value", () => {
btn.innerHTML = `count is ${count()}`;
});
el.appendChild(btn);
}
export default { render };
"""
_css = """
.counter-button {
background-image: linear-gradient(to right, #a1c4fd, #c2e9fb);
border: 0;
border-radius: 10px;
padding: 10px 50px;
color: white;
}
"""
value = traitlets.Int(0).tag(sync=True)
w = CounterWidget()
w.value = 60
w
By treating the model as the source of truth, whether Python kernel or JavaScript update value, the count displayed is correct. Additionally, a single model serves as the source of truth for all views of that model. Therefore when w
is displayed in another cell, the view is synchronized with the the output cell above.
w
But the state of a new widget instance is independent,
CounterWidget()