This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
shinywidgets is a Python package that renders ipywidgets inside Shiny for Python applications. It bridges the Jupyter widget ecosystem with Shiny's reactive framework.
uv sync --all-groups
uv run pre-commit install
uv run playwright install chromium
cd js && yarn install && yarn watch- Type checking:
make pyright(ormake py-check-types) - Linting/formatting check:
make py-check-format - Auto-format:
make py-format - Full quality check:
make check(format + types + unit tests) - Unit tests:
make test(ormake test-unit) - Run a single test:
uv run pytest tests/unit/test_foo.py::test_name - Playwright (browser) tests:
make test-playwright - All tests:
make test-all-local - Coverage:
make coverage - Build package:
make dist - Build JS:
cd js && yarn build - Watch JS:
cd js && yarn watch
The core challenge is establishing bidirectional communication between Python ipywidgets and the browser, mimicking how Jupyter kernels work but using Shiny's session/message infrastructure.
Python side (_comm.py, _shinywidgets.py):
ShinyCommreplacesipykernel.comm.Comm- sends widget state via Shiny custom messages (shinywidgets_comm_open,shinywidgets_comm_msg,shinywidgets_comm_close)init_shiny_widget()hooks intoWidget.on_widget_constructedto intercept all widget creation and establish comms- Widget state is serialized with buffer handling for binary data (base64 encoded since Shiny doesn't support binary messages)
- Global state maps in
_shinywidgets.py:SESSIONS,COMM_MANAGER,SESSION_WIDGET_ID_MAP,WIDGET_INSTANCE_MAP
JavaScript side (js/src/output.ts, js/src/comm.ts):
OutputManagerextends@jupyter-widgets/html-manager'sHTMLManagerto render widgets- Custom
ShinyCommimplements the comm protocol usingShiny.addCustomMessageHandler - Custom module loader (
shinyRequireLoader) handles widget JS dependencies via require.js
- User decorates function with
@render_widget(or specialized variants like@render_plotly) render_widget_base._render()calls user function, converts result viaas_widget()- Widget initialization triggers
init_shiny_widget()which sets up the comm - Render returns
{model_id, fill}to client - Client's
IPyWidgetOutput.renderValue()retrieves model from manager and displays view
Not all visualization objects are ipywidgets. as_widget() converts:
- altair: Chart ->
altair.JupyterChart - bokeh: Figure ->
jupyter_bokeh.BokehModel - plotly:
go.Figure->go.FigureWidget - pydeck: Deck ->
DeckGLWidget(via.show())
Handles dynamic loading of 3rd party widget JavaScript:
require_dependency()locates widget's nbextension files and creates HTMLDependency- Configures require.js paths so widgets can load their JS modules
- Falls back to CDN (unpkg.com) if local extension not found
set_layout_defaults() in _render_widget_base.py applies smart defaults for filling layouts:
- Detects user-specified heights to avoid overriding
- Handles package-specific layout APIs (plotly margins, altair container sizing)
- Works with Shiny's fill layout system
shinywidgets/_shinywidgets.py- Widget initialization, session management,reactive_read()shinywidgets/_render_widget_base.py-@render_widgetbase classshinywidgets/_render_widget.py- Thin renderer subclasses (render_plotly,render_altair, etc.)shinywidgets/_comm.py- Shiny-based comm implementationshinywidgets/_as_widget.py- Widget coercion functionsshinywidgets/_dependencies.py- JS dependency managementjs/src/output.ts- Browser-side output binding and message handlersjs/src/comm.ts- Browser-side comm protocol over Shiny message handlers
- Unit tests (
tests/unit/): Cover comm transport, serialization, rendering lifecycle, widget coercion, dependencies, reactivity, and layout defaults. Run withmake test-unit. - Playwright tests (
tests/playwright/): Browser-based integration tests that spin up real Shiny apps fromtests/apps/fixtures. Run withmake test-playwright. - Pyright type checking excludes
tests/playwright/(seepyproject.toml[tool.pyright]config). - CI runs format, types, and unit tests across Python 3.10-3.14; Playwright tests on 3.12 only.