posit-dev / posit-dev/shinyreact

Ship shiny-react bindings as npm packages for popular UI frameworks

Open
#32 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
14
Forks
3
Avg merge
9h 12m
Merged PRs (30d)
74

Description

Summary

Each example that uses a real component library (shadcn in ex 15/16) re-implements the same plumbing: Vite lib-mode IIFE, externalize React to window.shinyreact, register components, wire useShinyInput/useShinyOutput into a handful of components. That's ~50 lines of boilerplate per app, plus a vite.config.js people copy-paste.

We should publish a family of small npm packages — one per UI framework — that ship the bindings pre-wired. Users npm install @shinyreact/shadcn (or @shinyreact/mui, etc.) and get framework components that already speak Shiny.

Why

  • Removes the per-app Vite config boilerplate.
  • Gives each framework a single, versioned source of truth for the React-side contract.
  • Makes the "how do I use library X with Shiny?" answer a one-line install instead of an example to copy.
  • Bigger ecosystems (Material, Ant, Mantine) bring their own users who'd otherwise never touch shinyreact.

Candidate packages

Tier 1 (highest demand, likely owned by us):

  • @shinyreact/shadcn — wraps shadcn/ui primitives + lucide icons. Ex 15/16 collapse to ~5 lines.
  • @shinyreact/mui — Material UI v6.
  • @shinyreact/bootstrap — React Bootstrap (or react-bootstrap-icons).

Tier 2 (community-driven, we provide a template):

  • @shinyreact/mantine
  • @shinyreact/antd
  • @shinyreact/chakra
  • @shinyreact/headlessui + Tailwind
  • @shinyreact/radix (lower-level than shadcn)

Tier 3 (data-viz oriented, overlaps with #31):

  • @shinyreact/plotly
  • @shinyreact/echarts
  • @shinyreact/ag-grid

What each package contains

  • React components (or thin wrappers) that accept the underlying library's props plus an optional shinyId. With shinyId, the component round-trips state through useShinyInput and exposes commands via useShinyMessageHandler.
  • A pre-built IIFE bundle with React/ReactDOM externalized to window.shinyreact (matching ex 15's vite.config.js).
  • A registration entry point: importing the package side-effectfully calls window.shinyreact.registerComponents(...) so JSON specs reference the components by name.
  • Optional Python companion: a sibling Python package (shinyshadcn, shinymui, …) with extra_deps = [...] and any Spec/Element builders. Already established pattern — see CLAUDE.md §"Downstream package pattern".
  • TypeScript types for every component, including the round-trip input shapes (so #30's typegen has something to read).

Repo / publishing strategy

  • One monorepo per package family — likely posit-dev/shinyreact-bindings with each package at packages/shadcn, packages/mui, etc.
  • Or each non-trivial one gets its own repo (lighter ownership coupling).
  • Versioning policy: each binding pins a peer dependency on @shinyreact/core (the bundle we ship from js/). Major bumps in shinyreact core require a major bump in each binding.
  • A create-shinyreact-app scaffolder picks a binding and generates the matching app.py + vite.config.js + src/main.jsx.

Open questions

  • Do these need to be published as npm packages at all? For SPA-first apps the user already has a Vite build — they could install directly. But "copy this config" is friction; an npm package is the natural unit.
  • Granularity: one package per framework (@shinyreact/shadcn) or one package per component family (@shinyreact/shadcn-card, @shinyreact/shadcn-form)? Probably per-framework; tree-shaking handles unused components.
  • Python sibling packaging: do we ship the Python companion in the same repo as the JS binding (mirroring this repo's js/ + pkg-py/ layout) or split? Same repo is simpler; split is cleaner if a JS-only or Python-only audience shows up.
  • shadcn specifically is copy-paste-source, not an npm package. Our @shinyreact/shadcn would either (a) re-publish the shadcn primitives, which fights the upstream model, or (b) ship a CLI that runs npx shadcn add and patches in the Shiny wiring. (b) is more honest.
  • Theming: _brand.yml story for each framework. Bootstrap and shadcn already have brand.yml integration; MUI/Mantine/Antd would need adapters.
  • Maintenance burden: 6+ frameworks each tracking their own breaking changes is a lot of surface. We probably ship 2 (shadcn, MUI) and document a binding-author template for the rest.
  • Governance: which bindings does Posit own vs. community? Likely Posit owns shadcn + bootstrap (existing R parity); community owns the rest with a template repo.

Relationship to other work

  • Depends on #28 (Shiny client runtime as an npm package) — without that, every binding has to re-vendor or peer-depend on the IIFE bundle.
  • Pairs with #30 — typed inputs/outputs in Python comes "for free" if each binding ships TS types for its round-trip inputs.
  • Pairs with #31 — enhanced renderers are the natural Python counterpart; @shinyreact/plotly ships React side, shinyplotly Python ships matching render_plotly.

Out of scope

  • R package equivalents for each binding.
  • Vue / Svelte / Solid bindings — react-only for now.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading examples 15/16, the example 15 vite.config.js, and CLAUDE.md's “Downstream package pattern”; also review the existing js/ and pkg-py/ layouts. Done would require a decided package scope and publishing strategy, implemented bindings and companion packaging, documented types and registration, and working builds for the selected frameworks.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, react, typescript, vite
Domain
build-system, developer-experience, frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.