Build a Jupyter Widget with React and TypeScript

John Waidhofer
Jupyter Blog
Published in
4 min readJul 30, 2021

--

Photo by Adi Goldstein on Unsplash

When using a Jupyter Notebook to work on data science projects, I’ve found small user interface abstractions to be very useful. Scrubbing a slider or uploading a file can be more intuitive than editing a script and running it manually. This is especially true when a notebook is shared with others, since most people already have a basic knowledge about user interface elements.

Jupyter Widgets are fantastic tools for simplifying Jupyter Notebook workflows with custom user interfaces. While widgets are versatile and composable, sometimes the default implementations provided by Jupyter don’t have the exact functionality we are looking for. Luckily, we are able to create Custom Widgets to suit our needs using web technologies. To get an idea of how Custom Widgets work, we are going to build a sleek color picker for JupyterLab using React.

Setup

Before we can start coding, there is some basic boilerplate to download. Start by installing cookiecutter.

pip install cookiecutter

Then download the React widget boilerplate code.

cookiecutter https://github.com/Waidhoferj/jupyter-widget-react-cookiecutter.git

The cookiecutter template will guide us through some setup questions. The author_name, author_email, and github_project_name fields are the most important. We can leave the others blank or go with the default values.

Next, create a development environment using Anaconda:

conda create -n jupyter-react-widget -c conda-forge nodejs yarn python jupyterlabconda activate jupyter-react-widget

Every package we install for this project will now be contained in a neat bundle.

Inside the project directory created by cookiecutter, run the following script to install the dependencies that we’ll use to build the widget. Then connect our widget environment to JupyterLab:

pip install -e ".[test, examples]"jupyter labextension develop --overwrite .yarn run build

Thats it for the setup! Let’s see what the default widget can do.

Interacting with the Widget

To test out the widget, run jlpm watch in the project directory and open up JupyterLab with jupyter lab in another terminal window. In JuypterLab, open the notebook file located at <project>/examples/introduction.ipynb. Run all of the notebook cells to examine the state of the widget. In its current form, the widget displays a greeting alongside an input text field. Typing into the input field will update the target of the greeting. The value of the text box is automatically synced with w.value, allowing us to access the input’s contents as a Python string. With the default setup working, we can start designing our own custom widget.

Building a Color Picker

Let’s take a look at the architecture of a Custom Widget. The Jupyter Widget system allows developers to send data between Python and TypeScript using a Model-View-Controller Architecture. The Python Widget Model represents the state of the widget. The TypeScript Controller edits and responds to changes in the Python model based on user input. These updates are rendered in the notebook using React.

Data is passed from the Python model to the TypeScript controller to the React view and back

We can start building our color picker in example.py by adding a color property to the model.

The color property is set equal to the Unicode traitlet, which represents a string of characters. The .tag(sync=True) method syncs the value of the color property with the TypeScript widget state.

In widget.ts, we define the corresponding TypeScript representation of color in the defaultModelProperties object. This object mirrors the structure of the Python model, allowing us to access the model state in our frontend code.

Add color to the default model properties object

Now that we have defined our model, the rest of the work can be done in React. If you’d like to flex your web development skills and design a custom color picker, go for it! Alternatively, we can get a great plug-and-play interface by installing react-colorful:

jlpm add react-colorful

Create a ColorPicker.tsx file in the src folder. We can build out the component in a few lines of code:

The ColorPicker React component

Let’s walk through what’s happening here. At the top of the file, we import React, the react-colorful component, and a hook called useModelState. The useModelState hook operates like the useState hook but instead of accepting a default value as a parameter, it takes the name of a property from our Python model. The hook will automatically update the React view when the referenced property updates in Python. Also, the React widget can directly update the Python model with the setColor function. By passing color and setColor to the HexColorPicker, the Python widget model will reflect the chosen color whenever the user makes a selection in the interface.

To display the color picker in our notebook, add the component to ReactWidget.tsx, which is the top level React file in the widget system. Import the ColorPicker component at the top of the file and make it the return value of ReactWidget. We can delete all of the boilerplate within the ReactWidget component in the process. Additionally, delete the useModelState import at the top of the file, since it is no longer needed.

Add ColorPicker to ReactWidget

To test this out, restart the python kernel in JupyterLab and refresh the browser window. We will now see a color picker where the input field used to be. Pick a color and print out w.color to get the hex code in Python. Congrats! You now know how to create Jupyter Widgets using React!

The principles that we covered here can be applied to create more complex applications. To add additional properties, define them in both example.py and widget.ts, then interact with the data via the useModelState hook in a React component. Go build some amazing widgets!

Resources

--

--