nteract elements

Jupyter Widgets

Build notebook UIs with fully customizable widget components

Why nteract-elements widgets?

Traditional Jupyter widget frontends (@jupyter-widgets/html-manager) are designed for JupyterLab. They use Backbone.js for state management, have JupyterLab-specific styling, and are difficult to customize for standalone applications.

nteract-elements takes a different approach:

Traditionalnteract-elements
Backbone.js modelsPure React with useSyncExternalStore
JupyterLab stylingshadcn/ui primitives (fully customizable)
Monolithic managerModular: pick only what you need
Extension-focusedApp-focused

The result: widgets that look like your app, not JupyterLab.

Architecture

┌─────────────────────────────────────────────────────────────┐
│                      Your React App                         │
├─────────────────────────────────────────────────────────────┤
│                   WidgetStoreProvider                       │
│  ┌─────────────────────────────────────────────────────┐   │
│  │                    Widget Store                      │   │
│  │  • Manages all widget model state                    │   │
│  │  • Handles comm_open / comm_msg / comm_close         │   │
│  │  • Fine-grained subscriptions per model/key          │   │
│  └─────────────────────────────────────────────────────┘   │
│                           │                                 │
│         ┌─────────────────┼─────────────────┐              │
│         ▼                 ▼                 ▼              │
│   ┌──────────┐     ┌──────────┐     ┌──────────┐          │
│   │WidgetView│     │WidgetView│     │WidgetView│          │
│   └────┬─────┘     └────┬─────┘     └────┬─────┘          │
│        │                │                │                 │
│   ┌────▼─────┐    ┌─────▼────┐    ┌─────▼─────┐          │
│   │ IntSlider│    │AnyWidget │    │  VBox     │          │
│   │(built-in)│    │  (ESM)   │    │(container)│          │
│   └──────────┘    └──────────┘    └───────────┘          │
└─────────────────────────────────────────────────────────────┘

                           ▼ sendMessage()
                    ┌──────────────┐
                    │ Jupyter Kernel│
                    └──────────────┘

Components

Widget Store

The foundation. A pure React store that manages widget model state with:

  • Concurrent-safe state via useSyncExternalStore
  • Fine-grained subscriptions (subscribe to a single key, not the whole model)
  • IPY_MODEL_ reference resolution

Widget View

The router. Given a modelId, it renders the right component for each widget:

PropTypeDescription
modelIdstringThe comm_id of the widget model
classNamestringAdditional CSS classes for the container
Model closed? (e.g. tqdm with leave=False)
├── Yes → Render nothing
└── No → Model exists?
    ├── No → Show loading state
    └── Yes → Has _esm field?
        ├── Yes → Render with AnyWidgetView
        └── No → Has registered component?
            ├── Yes → Render built-in component
            └── No → Show unsupported widget fallback

AnyWidget View

ESM widget loader implementing the AFM interface:

  • Dynamic ESM loading (inline code or remote URLs)
  • CSS injection with automatic cleanup
  • Full two-way binding support

Built-in Controls

24 shadcn-backed widget components for standard ipywidgets:

  • Sliders: IntSlider, FloatSlider, IntRangeSlider, FloatRangeSlider
  • Progress: IntProgress, FloatProgress
  • Text: Text, Textarea, HTML
  • Selection: Dropdown, RadioButtons, ToggleButtons, SelectMultiple
  • Boolean: Checkbox, ToggleButton
  • Other: Button, ColorPicker
  • Containers: VBox, HBox, Box, GridBox, Accordion, Tab

Quick Start

# Install everything
npx shadcn@latest add @nteract/widget-view
npx shadcn@latest add @nteract/widget-controls

New to @nteract? pnpm dlx shadcn@latest registry add @nteract

import { WidgetStoreProvider, useWidgetStoreRequired } from "@/components/widgets/widget-store-context"
import { WidgetView } from "@/components/widgets/widget-view"
import "@/components/widgets/controls" // Register built-in widgets

function NotebookApp({ kernel }) {
  return (
    <WidgetStoreProvider sendMessage={(msg) => kernel.send(msg)}>
      <KernelBridge kernel={kernel} />
      {/* Render widgets by their comm_id */}
      <WidgetView modelId="widget-123" />
    </WidgetStoreProvider>
  )
}

// Must be inside WidgetStoreProvider to access the store
function KernelBridge({ kernel }) {
  const { handleMessage } = useWidgetStoreRequired()

  useEffect(() => {
    kernel.onMessage(handleMessage)
  }, [kernel, handleMessage])

  return null
}

For a complete integration example, see the runtimed sidecar which uses nteract-elements for full Jupyter widget support.

Customization

Every built-in widget uses shadcn/ui primitives. Customize them by:

  1. Theming - Modify CSS variables in your tailwind.config.js
  2. Override components - Register your own component for any model name
  3. Fork and modify - Copy a widget file and adjust as needed
import { registerWidget } from "@/components/widgets/widget-registry"

// Replace the default IntSlider with your custom version
registerWidget("IntSliderModel", MyCustomSlider)

On this page