If you’ve ever fought updateSliderInput, wrestled freezeReactiveValue, or watched renderUI destroy your DOM on every change — irid is for you.
irid lets you bind a reactiveVal directly to any DOM attribute. One reactive changes, one attribute updates. No ui/server split. No fragile input IDs to wire together. Just component functions with reactive state and DOM in the same scope.
library(irid)
library(bslib)
OldFaithful <- function() {
bins <- reactiveVal(30L)
page_fluid(
card(
card_body(
tags$label(\() paste0("Number of bins: ", bins())),
tags$input(
type = "range", min = "1", max = "50",
value = bins,
onInput = \(event) bins(as.integer(event$value))
),
PlotOutput(\() {
x <- faithful$waiting
b <- seq(min(x), max(x), length.out = bins() + 1)
hist(
x, breaks = b,
xlab = "Waiting time to next eruption (in mins)",
main = "Histogram of waiting times"
)
})
)
)
)
}
iridApp(OldFaithful)See more examples:
100% backward compatible
You don’t have to go all-in. Drop irid components into an existing Shiny app to handle complex interactivity with iridOutput/renderIrid:
ui <- fluidPage(
iridOutput("oldFaithful"),
tableOutput("summary")
)
server <- function(input, output, session) {
output$oldFaithful <- renderIrid(OldFaithful()) # irid component
output$summary <- renderTable(summary(faithful)) # classic Shiny
}
shinyApp(ui, server)Old Shiny inputs and irid components coexist in the same server scope. Migrate one renderUI at a time, or switch to iridApp when you’re ready.
See also: Shiny Interop example.
Installation
# install.packages("pak")
pak::pak("khusmann/irid")Learn more
See the Getting Started vignette to get started.
Why irid?
Irid is the iridescent layer that forms inside a shell. This package is a thin rendering layer that forms on top of Shiny. An extra layer of shiny, for Shiny.
Inspiration
irid brings ideas from modern JavaScript component frameworks to Shiny — especially Solid.js, which pioneered fine-grained reactivity where each change updates only the specific DOM node it’s bound to. Shiny’s reactive engine (reactiveVal, reactive, observe) was already close to this model; irid closes the gap by connecting it directly to the DOM the way Solid does. React’s component model and controlled input patterns were also an influence.
