Docs | Playground | DevTools
한국어 버전은 docs/README.ko.md를 확인해주세요.
Reduce blank time on CSR revisits by replaying the last visual state
FirstTx is for frequently revisited React apps that need to stay client-rendered because adopting SSR or a Next.js runtime is not practical. For infrequently used apps, the snapshot and persistence layers are usually not worth the added complexity.
FirstTx combines three client-side layers for CSR revisits:
- Prepaint: Replay a sanitized visual snapshot before the app bundle starts
- Local-First: Persist React model snapshots in IndexedDB and revalidate them from the server
- Tx: Run optimistic steps with retry and reverse-order compensating rollback
| Scenario overview | Verification criteria |
![]() |
![]() |
The Playground contains nine scenarios across Prepaint, Local-First, and Tx. Each scenario identifies one of three states: behavior that matches the current contract, a known limitation, or a demo that still needs revision. Runtime metrics are shown only when a measurement artifact is connected.
Run the scenarios in Playground or review the Playground guide.
| Choose a setup | Navigate by task |
![]() |
![]() |
The documentation is organized around adoption tasks: start with product fit, choose a setup, build each layer, verify behavior, troubleshoot failures, and look up exact public contracts.
Overview · Getting Started · Patterns · Troubleshooting · Reference
FirstTx adds reusable visual snapshot, persistent client cache, and compensation primitives while keeping a CSR architecture.
pnpm add @firsttx/prepaint @firsttx/local-first @firsttx/txPartial installation
- Revisit only:
pnpm add @firsttx/prepaint - Revisit + Sync:
pnpm add @firsttx/prepaint @firsttx/local-first - Sync + Tx:
pnpm add @firsttx/local-first @firsttx/tx
Tx requires Local-First as a dependency.
ESM-only. For CommonJS, use dynamic
import().
// vite.config.ts
import { firstTx } from '@firsttx/prepaint/plugin/vite';
export default defineConfig({
plugins: [
firstTx({
policy: { routes: ['/dashboard', '/cart'] },
}),
],
});Prepaint is off until
policy.routesexplicitly opts paths in. Snapshot restore always uses a non-interactive overlay outside the React root.
// main.tsx
import { createFirstTxRoot } from '@firsttx/prepaint';
createFirstTxRoot(document.getElementById('root')!, <App />);import { useSyncedModel } from '@firsttx/local-first';
function CartPage() {
const { data: cart } = useSyncedModel(CartModel, () => fetch('/api/cart').then((r) => r.json()));
if (!cart) return <Skeleton />;
return <CartList items={cart.items} />;
}For optimistic updates with Tx, see the Tx API reference.
| Use FirstTx | Consider Alternatives |
|---|---|
| Internal tools (CRM, dashboards) | Public landing pages → SSR/SSG |
| Frequent revisits (10+/day) | First-visit performance critical → SSR |
| No SEO requirements | Always need latest data → Server-driven UI |
| Browser | Min Version | ViewTransition |
|---|---|---|
| Chrome/Edge | 111+ | Full |
| Firefox | Latest | Graceful fallback |
| Safari | 16+ | Graceful fallback |
UI duplicates on refresh: Upgrade to @firsttx/prepaint@0.11.0 or later and mount React through createFirstTxRoot. No overlay option is required.
Frequently changing snapshot content: Add data-firsttx-volatile to content that should be cleared from the captured visual snapshot.
TypeScript errors: Add declare const __FIRSTTX_DEV__: boolean.
More at GitHub Issues.
MIT © joseph0926




