Custom widget#
The widget framework is based on the Comms framework, which enables the kernel to send and receive JSON to the front end. In order to create a custom widget, the widget must be defined both in the browser and in the Python kernel.
See also:
Python kernel#
DOMWidget#
To define a widget, it must inherit from the Widget
or DOMWidget
base class. If the widget is to be displayed in the Jupyter notebook, your widget should inherit from DOMWidget
. The DOMWidget
class itself inherits from the Widget
class.
_view_name
#
By adopting DOMWidget
, the widget framework is not informed which front-end widget should be linked to the back-end widget.
Instead, you have to specify this yourself using one of the following attributes:
_view_name
_view_module
_view_module_version
and if applicable
_model_name
_model_module
[1]:
import ipywidgets as widgets
from traitlets import Unicode, validate
class HelloWidget(widgets.DOMWidget):
_view_name = Unicode('HelloView').tag(sync=True)
_view_module = Unicode('hello').tag(sync=True)
_view_module_version = Unicode('0.1.0').tag(sync=True)
sync=True
-Traitlets#
Traitlets is a framework with which Python classes can have attributes with type checking, dynamically calculated default values and callbacks when changed. The sync=True
keyword argument tells the widget framework to synchronise the value with the browser; without it, the browser would not learn anything about _view_name
or _view_module
.
Frontend (JavaScript)#
Models and Views#
The front end of the IPython widget framework depends heavily on Backbone.js. Backbone.js is an Model View Controller (MVC) framework that automatically synchronises widgets defined in the backend with generic Backbone.js models in the frontend: the previously defined _view_name
characteristic is used by the widget framework to display the corresponding Backbone.js-View and link it to the
model.
Import @jupyter-widgets/base
#
First you have to use the @jupyter-widgets/base
module with the define
method of RequireJS.
[2]:
%%javascript
define('hello', ["@jupyter-widgets/base"], function(widgets) {
});
Define view#
Next we define the widget view class and we inherit from DOMWidgetView
with the .extend
method.
[3]:
%%javascript
require.undef('hello');
define('hello', ["@jupyter-widgets/base"], function(widgets) {
// Define the HelloView
var HelloView = widgets.DOMWidgetView.extend({
});
return {
HelloView: HelloView
}
});
render
method#
Finally, we still have to override the basic render
method to define a custom rendering logic. A handle to the standard DOM element of the widget can be called with this.el
. The el
property is the DOM element associated with the view.
[4]:
%%javascript
require.undef('hello');
define('hello', ["@jupyter-widgets/base"], function(widgets) {
var HelloView = widgets.DOMWidgetView.extend({
// Render the view.
render: function() {
this.el.textContent = 'Hello World!';
},
});
return {
HelloView: HelloView
};
});
Test#
The widget can now be displayed like any other widget with
[5]:
HelloWidget()
Stateful widget#
There’s not much you can do with the example above. To change this, you have to make the widget stateful. Instead of a static Hello World! Message, a string specified by the backend should be displayed. To do this, a new traitlet is first added. Use the name of value
here to stay consistent with the rest of the widget framework and to allow your widget to be used with interaction.
Create Jupyter widgets from a template#
A Cookiecutter is available with widget-cookiecutter. It contains an implementation for a placeholder widget Hello World. It also makes it easier for you to pack and distribute your Jupyter widgets.