Skip to content

Better htmlwidget support#1215

Open
thomasp85 wants to merge 10 commits into
mainfrom
native-HTML-widget
Open

Better htmlwidget support#1215
thomasp85 wants to merge 10 commits into
mainfrom
native-HTML-widget

Conversation

@thomasp85

Copy link
Copy Markdown
Collaborator

Fix #1034

This PR adds proper htmlwidget support for notebooks and inline quarto content. It follows suggestion 2 from @jmcphers and inlines the html directly, like the IRKernel. The reasons for this is mainly that supporting Jupyter Widgets would be a substantial addition with no user-visible upside since the one thing it provides (bidirectional communication) isn't possible with htmlwidgets anyway. If a compelling use case for bidirectional communication comes up we can revisit it.

We don't need pandoc or any other heavy dependency because the html is trivial to construct.

One wrinkle is that IRKernel defaults to deduplicating html dependencies from consecutive cells. This facility also exist in this PR but since Positrons notebook view renders each cell in isolation. Due to that the default for ark is to not deduplicate.

All changes only has an effect for notebooks. The standard path for viewer/plot pane remains unchanged

@thomasp85 thomasp85 marked this pull request as draft May 13, 2026 21:11
@thomasp85 thomasp85 marked this pull request as ready for review May 21, 2026 07:42
@thomasp85 thomasp85 requested a review from DavisVaughan May 21, 2026 07:43

@DavisVaughan DavisVaughan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code all seems good, but i have not actually been able to get this feature to work for me yet

Ping me on slack if the examples below (i.e. leaflet) work for you and we can try to figure out what I'm doing wrong before merging

Comment thread crates/ark/src/viewer.rs Outdated
Comment thread crates/ark/src/viewer.rs Outdated
Comment thread crates/ark/src/modules/positron/html_widgets.R Outdated
Comment thread crates/ark/src/viewer.rs Outdated
Comment thread crates/ark/src/modules/positron/html_widgets.R Outdated
Comment thread crates/ark/src/modules/positron/html_widgets.R
Comment thread crates/ark/src/modules/positron/html_widgets.R
Comment thread crates/ark/src/modules/positron/html_widgets.R Outdated
Comment thread crates/ark/src/viewer.rs Outdated
Comment thread crates/ark/src/viewer.rs

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this supposed to work?

library(leaflet)
m <- leaflet() %>% addTiles()
m

I tried it in a qmd with inline output turned on and got a blank output pane

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another one that doesn't work for me

library(billboarder)

# data
data("prod_par_filiere")

billboarder(data = prod_par_filiere) %>%
  bb_barchart(
    mapping = aes(x = annee, y = prod_hydraulique),
    color = "#102246"
  ) %>%
  bb_y_grid(show = TRUE) %>%
  bb_y_axis(
    tick = list(format = suffix("TWh")),
    label = list(
      text = "production (in terawatt-hours)",
      position = "outer-top"
    )
  ) %>%
  bb_legend(show = FALSE) %>%
  bb_labs(
    title = "French hydraulic production",
    caption = "Data source: RTE (https://opendata.reseaux-energies.fr/)"
  )

@thomasp85

thomasp85 commented Jun 10, 2026

Copy link
Copy Markdown
Collaborator Author

The related positron PR is posit-dev/positron#14150

This PR now handles a range of separate issues related to inline rendering of html widgets in quarto, the positron notebook and VS code notebook. A summary of the changes are:

  • Use fully qualified blocks for scripts and stylesheets instead of data: refs to avoid issues with execution order
  • Refire the wiring of html widgets at the end of the document as they may be injected after the onLoad event is fired
  • Guard against the AMD module builder when executing the widget scripts

@DavisVaughan DavisVaughan left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Combined with the Positron side PR, the two examples mentioned above work for me now in both a Quarto file with inline output enabled, and a ipynb file.

I can't comment much on the AMD bits or the forced staticRender() call for htmlwidgets, but if it seems required then sounds good.

@@ -3025,3 +3025,15 @@ pub unsafe extern "C-unwind" fn ps_get_active_request() -> anyhow::Result<SEXP>
let r_obj = RObject::try_from(json)?;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Still seeing the weird font issue in the pop out, probably want to at least open an issue for this.

i have a gut feeling the font thing is because in quartoOutputManager.ts in _openWebviewInViewer (which is what the popout button calls) it also does createNotebookOutputWebview, which may need to transition to the "raw" html version too (i.e. to createRawHtmlOutputWebview)

Screen.Recording.2026-06-08.at.10.27.10.AM.mov

Comment on lines +68 to +79
head_parts <- c(
'<meta charset="utf-8"/>',
AMD_GUARD_OPEN,
dep_html,
rendered$head
)

paste0(
"<!DOCTYPE html>\n",
"<html>\n",
"<head>\n",
paste(head_parts, collapse = "\n"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the amd_guard_open goes in the <head> but the amd_guard_close is outside of it? i dont know anything about this, it just smells odd

Comment on lines +50 to +51
// Defensive reset in case a sibling test leaked the option.
code.push_str("options(ark.html_widget.deduplicate = NULL)\n");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should remove all of these "defensive resets"

With nextest, all Rust tests run in their own individual process, so this is a non issue and will only confuse future us

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.

In notebook mode, emit HTML widgets as static, embeddable HTML

2 participants