Maven Central Last Commit GitHub Scala Version ScalaJS Version
A React-inspired frontend library for Scala.js. Build user interfaces with function
components, hooks, and a typed DSL: an immutable VNode tree describes the UI, and a
reconciler diffs each new tree against the live DOM and patches only what changed.
riposte β in fencing, the swift counter-thrust that follows a parry. Here: an event or state change comes in, the reconciler diffs (parry), and patches the DOM in answer (riposte). The word traces back through Italian sword-fighting to Latin respondΔre β "to respond."
import io.github.edadma.riposte.* import org.scalajs.dom val Counter = view { val (count, _, update) = useState(0) button(onClick := (_ => update(_ + 1)), s"Count: $count") } @main def run(): Unit = render(Counter(), dom.document.getElementById("app"))
Full documentation lives at riposte.edadma.dev.
- Getting started β install and mount your first component
- Guide β components & the DSL, hooks, shared state, routing, data fetching, forms
- Component library (salle) β styled, skinnable widgets, one page per component
- Reference β the published modules and their APIs
Riposte ships as six independently published artifacts under io.github.edadma; the
siblings depend on the core transitively. The core itself is a thin DOM host over
vdom β a host-agnostic engine (the VNode model, reconciler, hooks runtime, and
scheduler) that names no platform type and is pulled in transitively. You depend on
riposte, not vdom.
| Artifact | What it gives you |
|---|---|
riposte |
The core: components, hooks, the DSL, rendering |
vdom |
The host-agnostic engine riposte hosts (transitive) |
riposte-atoms |
Jotai-inspired atomic shared state |
riposte-router |
Client-side routing for single-page apps |
riposte-query |
TanStack-style async server-state cache (built on atoms) |
riposte-forms |
react-hook-form-style form layer (uncontrolled fields, validation) |
riposte-salle |
Styled, skinnable component library β form controls (incl. Segmented), Image/Lightbox, Carousel/Hero, Badge/Tag, Skeleton, Spinner/Progress, Empty, Descriptions, Pagination, Dropdown, Tabs, Breadcrumb, Modal/Drawer/Toast/Tooltip, Layout/Navbar/Footer shell, grid + masonry layout, theming |
libraryDependencies += "io.github.edadma" %%% "riposte" % "0.3.0" libraryDependencies += "io.github.edadma" %%% "riposte-atoms" % "0.3.0" libraryDependencies += "io.github.edadma" %%% "riposte-router" % "0.3.0" libraryDependencies += "io.github.edadma" %%% "riposte-query" % "0.3.0" libraryDependencies += "io.github.edadma" %%% "riposte-forms" % "0.3.0" libraryDependencies += "io.github.edadma" %%% "riposte-salle" % "0.3.0"
vdom/β the host-agnostic core (VNode, reconciler, hooks, scheduler,HostConfig), acrossProject(JS, JVM); riposte hosts the JS build, the JVM build runs headless reconciler/hooks testscore/β theripostelibrary: the DOM host forvdom(itsHostConfig, the HTML/SVG DSL, the DOM hooks) plus the re-export of vdom's API underio.github.edadma.riposteatoms/βriposte-atoms, atomic state built on the core'suseSyncExternalStoreseamrouter/βriposte-router, client-side routing on the same public seamquery/βriposte-query, an async server-state cache built onriposte-atomsforms/βriposte-forms, a react-hook-form-style form layer on the core's public APIsalle/βriposte-salle, a styled component library built on the core's DSL + hooksdemo/β a runnable showcase (its own subproject, never published)salle-demo/β a runnable showcase for salle (its own subproject, never published)salle-e2e/β a Playwright harness driving salle components in a real browser (never published)- the repo root is a thin aggregator; a task run there fans out to every module
sbt test # every module (vdom JVM+JS, core + atoms + router + query + forms + salle) sbt vdomJVM/test # the host-agnostic core, headless on the JVM (TestHost) sbt vdomJS/test # the same suite on JS sbt riposte/test # just the library (project id is `riposte`, in core/) sbt atoms/test # just the atoms module sbt router/test # just the router module sbt query/test # just the query module sbt forms/test # just the forms module sbt salle/test # just the salle component library sbt demo/fastLinkJS # build the demo's JS sbt salleDemo/fastLinkJS # build the salle demo's JS
Tests run under a real DOM via jsdom (npm install fetches it). To see the demo, build
its JS, then serve demo/ (e.g. cd demo && python3 -m http.server) and open index.html.
The salle component library also has a Playwright suite that drives the components in a
real Chromium (salle-e2e/), covering interactions jsdom can't β focus, pointer, layout:
npm run e2e # build the harness bundle, then run the Playwright specs npm run e2e:build # just build the harness JS (sbt salleE2E/fastLinkJS) npm run e2e:run # run the specs against an already-built bundle npm run e2e:ui # the same, in Playwright's interactive UI
ISC