Skip to content

fix: preserve widget state in HTML export#8933

Draft
dondetir wants to merge 1 commit intomarimo-team:mainfrom
dondetir:fix/html-export-preserve-widget-state
Draft

fix: preserve widget state in HTML export#8933
dondetir wants to merge 1 commit intomarimo-team:mainfrom
dondetir:fix/html-export-preserve-widget-state

Conversation

@dondetir
Copy link
Copy Markdown

This pull request was authored with assistance from a coding agent.

Summary

Preserve widget states (dropdowns, sliders, plotly selections) in HTML exports instead of resetting them to defaults.

Problem

When exporting a notebook as HTML via "Download as HTML (except code)", widget states reset to their construction-time defaults. A dropdown set to "Critical" exports as "Normal"; a chart filtered to 2 countries exports showing all countries. The reader sees something different from what the author intended to share.

Root cause: session_view.ui_values (the dict tracking all widget interactions) is never included in the HTML export serialization.

Solution

Three coordinated changes that mirror the existing live-session reconnect pattern (handleKernelReady in handlers.ts:162-166):

  1. Python schema — Add ui_values: Optional[dict[str, Any]] to NotebookSessionV1
  2. Python serialization — Include ui_values=dict(view.ui_values) in serialize_session_view()
  3. Frontend — In mount.tsx, read session.ui_values and pre-populate UI_ELEMENT_REGISTRY before React renders widgets in static mode

Backward compatible

ui_values is Optional/nullable with #[serde(default)]-equivalent behavior. Old HTML exports without the field continue to work (widgets fall back to data-initial-value as before).

Re: PII concern

Per @mscolnick's note — widget values are already visible in the rendered cell HTML output, so this doesn't expose new data. Happy to add a changelog entry noting this behavior change.

Files changed (10 files, +35/-8 lines)

File Change
marimo/_schemas/session.py Added ui_values: Optional[dict[str, Any]]
marimo/_session/state/serialize.py Include ui_values in serialization
marimo/_schemas/generated/session.yaml Updated OpenAPI schema
packages/openapi/src/session.ts Updated TypeScript type
frontend/src/mount.tsx Hydrate UI_ELEMENT_REGISTRY in static mode
tests/.../snapshots/*.json (5 files) Updated snapshot expectations

Tests

  • Serialization tests: 32 passed, 1 xfailed
  • Python lint (ruff): clean
  • Python format (ruff): clean
  • Frontend lint (biome): clean

Closes #8613

Include session_view.ui_values in the HTML export serialization so
widget states (dropdowns, sliders, plotly selections) are preserved
instead of resetting to defaults.

Changes:
- Add ui_values field to NotebookSessionV1 schema (Python, YAML, TS)
- Serialize ui_values in serialize_session_view()
- Hydrate UI_ELEMENT_REGISTRY from ui_values in static mode (mount.tsx)

The frontend hydration mirrors the existing pattern in handleKernelReady
for live session reconnects (handlers.ts:162-166).

Backward compatible: ui_values is Optional/nullable, so old HTML exports
without it continue to work (widgets fall back to data-initial-value).

Closes marimo-team#8613
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 31, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
marimo-docs Ready Ready Preview, Comment Mar 31, 2026 1:47am

Request Review

@dondetir
Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 31, 2026

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@dmadisetti
Copy link
Copy Markdown
Collaborator

@peter-gy I think you had an idea for propagating UI element values?
Surprisingly light PR @dondetir is this still under construction? Things may get hairier soon

@dondetir
Copy link
Copy Markdown
Author

Thanks @dmadisetti! Yes, still a draft — wanted to get the approach in front of you early rather than build out in isolation.

The current change is intentionally minimal: serialize session_view.ui_values into the HTML export and hydrate UI_ELEMENT_REGISTRY on the frontend before render — mirroring what handleKernelReady already does for live session reconnects.

I stress-tested the edge cases from #8613:

  • Dropdowns, sliders, text inputs, batch/form/array — values round-trip correctly through JSON serialization
  • Plotly selection/lasso — preserved (stored in ui_values). Legend visibility is client-side Plotly.js state and was never in ui_values — out of scope here
  • File browser — selected files are restored, but browsing still needs a live kernel (pre-existing limitation of static export)
  • TiminginitStore() runs synchronously before root.render(), so the registry is populated before any widget mounts
  • Backward compat — field is Optional/nullable, old exports without it work fine

That said, I expect there are dimensions I haven't considered — happy to hear what @peter-gy had in mind for propagating UI element values. If there's a broader approach this should fit into, I'm glad to adapt or pivot.

Keeping as draft until we're aligned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export as HTML doesn't preserve control states

2 participants