Skip to contents

Add Alpine.js reactivity to your R web apps — without writing JavaScript.

Alpine.js handles small, local interactions through HTML attributes (x-data, x-show, x-on:click…). alpiner is an R wrapper that lets you attach those attributes to any htmltools tag from R, and works hand-in-hand with {htmxr} for the server-side round-trips.

Installation

pak::pak("hyperverse-r/alpiner")

How it works

htmxr handles server interactions (a click sends an HTTP request, the response is swapped into the DOM). alpiner handles local interactions that never touch the server — toggles, counters, show/hide, form validation hints. Together they cover the full reactivity spectrum without a single line of JavaScript in your application code.

x_set() is the only primitive: it appends Alpine.js directives to an existing tag.

tags$div() |> x_set(data = "{ open: false }")
tags$button() |> x_set(on = list(click = "open = !open"))
tags$div() |> x_set(show = "open")

Example — local counter

A standalone counter, no server round-trip. The page is built with hx_page() from htmxr; Alpine is wired up via hx_head(x_script()).

library(htmxr)
library(alpiner)

#* @get /
#* @parser none
#* @serializer html
function() {
  hx_page(
    hx_head(x_script(), title = "Alpine.js Counter"),
    tags$div(
      tags$p(
        tags$span("0") |> x_set(text = "count"),
        style = "font-size: 3rem; font-weight: bold;"
      ),
      tags$button(`@click` = "count++", "+"),
      tags$button(`@click` = "count--", "-")
    ) |> x_set(data = "{ count: 0 }")
  )
}

Run it

x_run_example("counter")

A second example, htmx, demonstrates combining alpiner (local state) with htmxr (server-driven content) in the same page.

Design philosophy

  • One primitivex_set() is enough. No wrappers, no DSL, no hidden state machine. You write Alpine.js, in R syntax.

  • HTML over abstraction — Every x_set() call appends standard x-* attributes to an htmltools tag. What you write in R is what lands in the browser.

  • CSS-agnostic — No styling assumptions. Bring your own framework, or none.

  • Pairs with htmxr — Local state stays in the browser (Alpine.js). Anything that needs server logic goes through htmx. Two scopes, one mental model.

Code of Conduct

Please note that the alpiner project is released with a Contributor Code of Conduct. By contributing to this project, you agree to abide by its terms.