Building Modern R-Powered Web Tools with Plumber + HTMX + Highcharts

Plumber lets you expose R functions as REST endpoints, while HTMX gives you dynamic page updates with almost no JavaScript. Combine them with Highcharts (via the excellent highcharter package) and you get beautiful, interactive dashboards served straight from R — lightweight, fast, and fully under your control.

Below is a complete static demo using the classic mtcars dataset. The chart is rendered directly in the browser (no server needed for this blog post), but the code examples show exactly how you’d generate and serve the same chart from a Plumber API.

Interactive Demo: MPG vs Weight (colored by cylinders)

What a Real Plumber Endpoint Would Return

Here’s the exact R code you’d use in a Plumber API to generate and serve the same interactive chart as an HTML fragment (perfect for HTMX to inject):

library(plumber)
library(highcharter)
library(dplyr)
library(htmltools)

#* Serve interactive mtcars scatter chart
#* @get /mtcars-chart
#* @serializer html
function() {
  chart <- mtcars |>
    mutate(cyl = as.factor(cyl)) |>
    hchart(
      "scatter",
      hcaes(x = wt, y = mpg, group = cyl),
      name = cyl
    ) |>
    hc_title(text = "MPG vs Weight — mtcars dataset") |>
    hc_subtitle(text = "Served live from R via Plumber") |>
    hc_xAxis(title = list(text = "Weight (1000 lbs)")) |>
    hc_yAxis(title = list(text = "Miles per Gallon")) |>
    hc_tooltip(pointFormat = "<b>{point.name}</b><br>Weight: {point.wt}<br>MPG: {point.mpg}<br>Cyl: {point.cyl}") |>
    hc_chart(zoomType = "xy") |>
    hc_add_theme(hc_theme_smpl())

  # Return standalone HTML fragment
  tagList(
    tags$div(id = "mtcars-chart", style = "width:100%; height:500px;"),
    htmlwidgets::as_widget(chart)
  ) |> as.character()
}
<div 
  class="bg-white rounded-xl shadow-lg p-6 my-8"
  hx-get="https://your-api.example.com/mtcars-chart"
  hx-trigger="load"
  hx-swap="innerHTML"
>
  Loading chart from R...
</div>

Why This Pattern Works So Well

  • R handles all data processing and chart rendering (highcharter → full Highcharts widget)
  • Plumber returns ready-to-insert HTML (no client-side JSON parsing needed)
  • HTMX swaps in the new chart instantly when filters change or on page load
  • Zero build complexity on the frontend — just Tailwind + HTMX + Alpine if desired
  • Easy to deploy (Docker, Render, Fly.io, etc.)

Increasingly, I see this approach as simple yet elegant. It combines the power of R with the simplicity of modern web tools.

phil@virtus-solutions.io

#rstats #plumber #htmx #highcharts #dataviz #webdev