Render react in custom (ipywidgets) widget

I would like to render a React component to a DOMWidgetView, or to phrase it more general, render a React component to a custom widget based on ipywidgets.

The documentation Building a Custom Widget - Email widget — Jupyter Widgets 8.1.5 documentation shows how to render the frontend side of a custom widget:

export class EmailView extends DOMWidgetView {
  render() {
    this.el.classList.add('custom-widget');

    this.value_changed();
    this.model.on('change:value', this.value_changed, this);
  }

  value_changed() {
    this.el.textContent = this.model.get('value');
  }
}

Then we have the react-widget example at extension-examples/react-widget at main · jupyterlab/extension-examples · GitHub
In src/widget.tsx it defines a ReactWidget:

export class CounterWidget extends ReactWidget {
    /**
     * Constructs a new CounterWidget.
     */
    constructor() {
      super();
      this.addClass('jp-react-widget');
    }
  
    render(): JSX.Element {
      return <CounterComponent />;
    }
  }

How can I combine the two? Say, I want to render the CounterComponent into the EmailView. Is this possible?
ReactWidget is derived from lumino Widget. DOMWidgetView is derived from jupyter-widgets WidgetView. There is no common ancestor in their class hierarchies.

I wonder if somebody has solved this before.

Thank you
Kevin

1 Like

If you want to create a widget with React I would recommend checking out anywidget – it’s a library that greatly simplifies the development of custom widgets.

They have a CLI to bootstrap a new widget project:

npm create anywidget@latest

There’s a “React” option there that will set up a React-based widget so you can quickly try things out.

1 Like

Thank you very much! anywidget looks like an option if I cannot solve this using ipywidgets alone.

When I heard about anywidget a few months ago for the first time, I couldn’t take it serious, because the getting-started examples gave the impression that the frontend js code had to be defined in a multiline python string. After I closer look I understand that it can also import a js file, and also bundling tsx code seems to be possible. Very nice.

Still, I’d prefer a solution without anywidget. Is it possible?

Unfortunately, I have to customize the widget serialization of my models as explained here:

https://ipywidgets.readthedocs.io/en/7.x/examples/Widget%20Low%20Level.html#Custom-serialization-and-de-serialization-on-the-JavaScript-side

My DOMWidget (or AnyWidget, if possible) has some members like
childx = traitlets.Instance(X).tag(sync=True)
where X is another Widget. If I cannot (de)serialize these members as described in the link, such nested members cannot be used. This seems to be a limitation of anywidget.

Container widgets and serialization are kind of over my head to be honest. There are some possibly relevant topics in anywidget discussions:

I’m afraid I can’t contribute more on this topic =).