Skip to main content

shinyreact

React UI infrastructure for Shiny — Python and R

With shinyreact, the Shiny server (Python or R) contains only reactive computation, and the UI is a React client you own. shinyreact is the bridge between the two; it ships zero UI components itself.

One JavaScript bundle backs both languages, so the same React client works identically against an app.py or an app.R server.

The ui.tsx pattern

  1. The app file bootstraps a static page — set_react_page() (Python Express) or page_react() (Python Core, R).
  2. Your React client, conventionally ui.tsx (compiled to www/ui.js, discovered automatically), renders the UI.
  3. Client and server talk through hooks: useShinyInput sends values to the server, useShinyOutputValue receives what reactive_output publishes, and useShinyMessageHandler receives send_message() pushes.
from shiny.express import input
from shinyreact import reactive_output, set_react_page

set_react_page()


@reactive_output
def greeting():
    return {"message": f"Hello, {input.name()}"}
library(shiny)
library(shinyreact)

server <- function(input, output, session) {
  output$greeting <- reactive_output({
    list(message = paste0("Hello, ", input$name))
  })
}

shinyApp(page_react(), server)
const { React, ReactDOM, useShinyInput, useShinyOutputValue } = window.shinyreact;

function App() {
  const [name, setName] = useShinyInput("name", "world");
  const greeting = useShinyOutputValue("greeting");
  return (
    <>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <p>{greeting?.message}</p>
    </>
  );
}

// No mount div in the generated page — append one to <body>.
ReactDOM.createRoot(document.body.appendChild(document.createElement("div"))).render(<App />);

Installation

shinyreact is pre-release. Install from GitHub:

pip install "git+https://github.com/posit-dev/shinyreact.git"
pak::pak("posit-dev/shinyreact/pkg-r")

The JS hooks come with the server package — set_react_page() / page_react() serve shinyreact.js, which installs them at window.shinyreact. Apps with a bundler can instead npm install @posit-dev/shinyreact and pass shinyreact_js="client" to the page entry point.

Agent Skills

Both packages ship two Agent Skills so a coding agent can build a shinyreact app without you pasting documentation into it: shinyreact-build-app builds a ui.tsx-pattern app from scratch, and shinyreact-convert-app ports an existing Shiny app to the pattern.

The fastest starter template is the skill itself. With the shinyreact skills installed, paste this into your agent (swap in R if that is your server):

Using the `/shinyreact-build-app` skill, scaffold a new shinyreact app in this
directory with a Python server. Set up the Vite build (src/ui.tsx compiled to
www/ui.js) and a hello-world UI: a text input whose value the server greets by
name. Run the build and start the app.

Reference

Python set_react_page(), page_react(), ReactApp, reactive_output, send_message(), …
R page_react(), reactive_output(), send_message(), …
JS useShinyInput, useShinyOutputValue, useShinyMessageHandler, ShinyOutput, …
Examples Runnable apps, from no-build www/ui.js to Vite + HMR
Design Why the pattern looks the way it does