Skip to contents

sherpa is a lightweight bridge between R Shiny and Alpine.js. It allows you to build highly reactive user interfaces by handling state and transitions in the browser while keeping your business logic in R.

Key Features

  • ✅ The s$ Proxy: A “Sherpa-aware” version of shiny::tags that automatically handles Alpine attributes without the need for the !!! (unquote-splice) operator.

  • ✅ R-Native Directives: All core Alpine.js directives (x-data, x-model, x-for, etc.) available as standard R functions with support for modifiers and optional arguments.

  • ✅ AlpineStore (R6): Seamlessly sync server-side R reactive values to Alpine.js global stores.

  • 📋 TODO: Auto-Binding: Automatically handles Shiny input/output binding for dynamically generated Alpine content.

  • 📋 TODO: Supports Alpine.js Plugins, with special accomodations for Alpine AJAX

Installation

You can install the development version of sherpa like so:

devtools::install_github("teebusch/sherpa")

Quick Start

A Simple Counter (Pure Frontend)

Use the s$ proxy for Shiny-Tags to easily inject Alpine logic into your Shiny-UI.

library(shiny)
library(sherpa)

ui <- fluidPage(
  use_alpine(),
  s$div(
    x_data("{ count: 0 }"),
    s$h2("Counter: ", s$span(x_text("count"))),
    s$button("Increment", x_click("count++"), class = "btn btn-primary")
  )
)

server <- function(input, output, session) {}

shinyApp(ui, server)

Server-Synced State (via AlpineStore)

ui <- fluidPage(
  use_alpine(stores = "status"),
  s$div(
    s$h3("Server Status: ", s$span(x_text("$store.status.label"))),
    s$div(
      x_bind("class", "$store.status.connected ? 'text-success' : 'text-danger'"),
      x_text("$store.status.message")
    )
  )
)

server <- function(input, output, session) {
  app_state <- AlpineStore$new("status")
  app_state$init(list(label = "Pending", connected = FALSE, message = "Waiting..."))
  
  observe({
    invalidateLater(2000)
    app_state$update("label", "Live")
    app_state$update("connected", TRUE)
    app_state$update("message", paste("Last sync:", Sys.time()))
  })
}

The “Way of the Sherpa” (Rules of Engagement)

  • Use the Proxy: Always use stagname()(e.g.,stag_name() (e.g., sdiv()) instead of tags$div() when you want to pass x_ helpers.

  • No Bangs: Because of the s$ proxy, you do not need the !!! operator. Just pass the helper: s$div(x_data(NA)).

  • Declare Stores: Pass your store names to use_alpine(stores = c(“myStore”)) to prevent “undefined” errors during page load.

Available Directive Helpers

R Helper Alpine directive What it does
x_data() x-data Defines a component and its reactive data.
x_bind() x-bind Dynamically binds HTML attributes (e.g. class, disabled).
x_on() x-on Listens for browser events (shortcut: x_click, x_change).
x_text() x-text Updates the inner text of an element dynamically.
x_html() x-html Updates the inner HTML of an element (use with caution).
x_model() x-model Creates two-way data binding on input elements.
x_show() x-show Toggles visibility via CSS (display: none).
x_transition() x-transition Applies smooth CSS transitions for entries and exits.
x_for() x-for Loops over data to create elements (must use <template>).
x_if() x-if Conditionally adds/removes elements (must use <template>).
x_init() x-init Runs JavaScript code when the element is initialized.
x_effect() x-effect Runs a script when a reactive dependency changes.
x_ref() x-ref Utility for accessing DOM-Elements directly.
x_cloak() x-cloak Hides elements until Alpine has finished loading.
x_ignore x-cloak Lets Alpine ignore an element.
x_modelable() x-modelable Expose Alpine properties as the target of x-model.

Directive missing? Use x_attr_builder() to create your own.

See the Alpine Docs for more details