On this page

Raw Markdown View this page on GitHub

Examples

The example/ directory contains 12 applications in 11 modules.

Run an example

Each example is a separate Go module. Its go.mod replaces github.com/romshark/datapages with the surrounding checkout at ../../. Clone the repository and run commands from the example directory:

git clone https://github.com/romshark/datapages
cd datapages/example/todolist
go run ./cmd/server

The generated code and the frontend bundles are committed, and go run needs only Go. The examples that need more say so below.

datapages watch regenerates the code with the CLI on the PATH. Install the CLI from the same checkout, in the repository root:

go install ./cmd/datapages

A release of the CLI generates the code of its release, which does not compile against the checkout, with errors such as not enough arguments in call to s.streams.Handle.

Note

Fast shim, Offline cache and Docs install a service worker for their server address. The browser keeps the worker after the server stops. It can answer requests from the next example at that address with cached files. Before running another example there, unregister the worker under Application and Service workers in the browser developer tools.

Each example also has the agent instructions that datapages init writes. See AI agents.

Counter

A counter that every open tab updates, built 2 times in 1 module. app/simple is the smallest Datapages application, and the Introduction walks through it. app/fancy is the same model with animated digits.

Features:

  • A page and an action with a query parameter. See Pages and routes and Actions.
  • An event, its dispatcher and an On handler, over the in-memory broker. See Events.
  • 2 app packages, 2 generated packages and 2 entry points, with event subjects that carry the name of the application. See Multiple applications.

Run:

go run ./cmd/simple   # http://localhost:8080/
go run ./cmd/fancy    # http://localhost:8081/
datapages watch --app app/simple

The code is in example/counter.

Todo list

A collaborative todo list. A change in 1 tab appears in every open tab, and each tab keeps its own filter, sort order and search. It follows the Tao of Datastar. Actions send commands, and the server answers over SSE with the whole list rendered again. The data lives in memory.

Features:

  • Per-tab state in datapages.State[T], set in StreamOpen and read by the event handlers. See Per-tab state.
  • EventTodoUpdated, which every open tab handles. See Events.
  • Query fields with reflectsignal tags, which keep the filter, sort order and search in the URL. See Pages and routes.
  • POST, PUT and DELETE actions on pages and on App. See Actions.
  • A custom 404 page and static files. See Static assets.

Run:

go run ./cmd/server   # http://localhost:8080/
datapages watch       # http://localhost:7331/

The code is in example/todolist.

Calculator

A calculator that evaluates expressions on the server with shopspring/decimal. Each button press sends 3 signals to a QUERY action, which answers with an SSE patch of the calculator and its signals. The server keeps no state between requests, and the page has no stream. The same app package runs as an HTTP server and as a Wails v3 desktop app, as the FAQ describes.

Features:

  • PageIndex.QUERYInput with datapages.Signals, datapages.Query and datapages.SSE. See Actions.
  • Static files. See Static assets.
  • In the desktop app, datapages.WithNoSSECompression, datapages.WithNoResponseCompression and datapages.WithNoAssetsCompression, because its only client is a webview on the loopback interface. See Performance.
  • Tests with net/http/httptest. See Testing.

Run with Mage:

mage runServer        # http://localhost:8080/
mage runDesktop       # the desktop app
mage dev              # datapages watch, http://localhost:7331/
mage testUIWorkflows  # UI tests with Maestro

mage runServer and mage runDesktop run templ generate and datapages gen first. go run ./cmd/server starts the HTTP server without Mage. The desktop app uses cgo and needs a C compiler. mage testUIWorkflows needs Maestro.

The code is in example/calculator.

Classifieds

A classifieds marketplace with sign-in, posts, search, user pages, chat with typing indicators and unread counts, and a settings page that ends sessions. It runs on NATS and comes with Prometheus metrics, Grafana dashboards and k6 load tests.

Features:

  • Sessions in the NATS key-value store, NewSession at sign-in, CloseSession at sign-out, and closing the other sessions of a user. See Sessions and auth.
  • Events addressed to 1 user with datapages.SubjectUser, and a stream embed, Base, whose On handlers every page except PageLogin and PageError500 shares. See Events.
  • Per-tab state for the chat a tab has open, seeded from a signal in StreamOpen. See Per-tab state.
  • Search through a QUERY action, with reflectsignal query fields that keep the search in the URL. See Pages and routes.
  • PageError404, PageError500 and RecoverError. See Actions.
  • The natscore broker, Prometheus metrics with collectors of the application, and TLS. See Deployment.
  • A self-hosted Datastar bundle passed to datapages.WithDatastarJS. See Static assets.
  • A Toxiproxy preset with overrides for 1 action, 1 page stream and the static files. See Slow and failing networks.

Run, with Docker:

make dev    # http://localhost:7331/
make down

make dev starts NATS, Prometheus and Grafana in containers, then runs datapages watch. The services use these addresses:

The Flaky network preset delays responses, limits bandwidth, delays sent messages and resets the messages stream. make load runs the k6 load test. make stage runs the server with TLS through sudo; it needs mkcert and the HOST from .env.stage in /etc/hosts.

The code is in example/classifieds.

Tailwind CSS

A static page styled with Tailwind CSS v4. A custom watcher of datapages watch rebuilds app/static/output.css when a .templ file or input.tw.css changes, and a second one reloads the browser when a static file changes.

Features:

Run, with Node.js and npm:

make dev              # npm install, the CSS build and datapages watch, http://localhost:7331/
go run ./cmd/server   # with the committed output.css, http://localhost:8080/

The code is in example/tailwindcss.

Web Components

A landing page with 2 Web Components in TypeScript, <wc-counter> without dependencies and <wc-particles> built with Lit. A custom watcher bundles them with esbuild into app/static/bundle.js on every change and reloads the browser.

Features:

Run, with Node.js:

make npm-install
make dev              # http://localhost:7331/

The code is in example/webcomponents.

SQLite sessions

Sign-in and registration with sessions that a custom sessions.Manager stores in SQLite through sqinn-go, without cgo. The rest of the application is the smallest one that uses the store.

Features:

  • A session manager with the 5 methods of sessions.Manager, and DeleteExpired scheduled by cmd/server/main.go. See Sessions and auth.
  • NewSession at sign-in and registration, and CloseSession at sign-out.
  • EventSessionClosed, addressed with datapages.SubjectUser, which redirects the other tabs of the closed session. See Events.
  • QUERY actions that validate the forms while the visitor types. See Actions.

Run:

make dev              # datapages watch, http://localhost:7331/

The first start creates 3 users, alice@example.com, bob@example.com and carol@example.com, all with the password password123. The database is sqlitesessions.db in the working directory, and SESSION_DB_PATH changes it. sqinn-go ships a prebuilt sqinn binary, and SQINN_PATH selects another.

The code is in example/sqlitesessions.

Fast shim

Pages that take 900 ms to render. / and /subpage show a cached shim at once and the live page when it arrives. /noshim and /noshim2 wait for the live page on every visit.

Features:

  • pageCache.SetShim with a version that changes with the markup of the shim. See Offline and shims.
  • The offline module installed with offline.WithServiceWorker, for an app without PageOffline.

Run:

go run ./cmd/server   # http://localhost:8080/

Reload a page with a shim to see the shim before the live page. The worker runs only on HTTPS and on localhost.

The code is in example/fast-shim.

Offline cache

A ticketing app with live search, purchases and QR-code tickets, which stay available offline. The data lives in memory. The demo accounts are moviebuff and jazzfan, with the password demopass.

Features:

  • Snapshots written with pageCache.Set, ClearAll at sign-in and sign-out, PageOffline and the generated WithOffline, and a self-hosted Datastar bundle. See Offline and shims.
  • Sessions with the in-memory session manager, and a redirect to sign-in with ?next= from protected pages. See Sessions and auth.
  • Live search through a QUERY action, with the search kept in ?q=. See Actions and Pages and routes.
  • PageError404, PageError500 and tests with net/http/httptest. See Testing.

Run:

go run ./cmd/server   # http://localhost:8080/

To see the offline pages, sign in, buy or open a ticket, stop the server and reload. The ticket still opens, and a show you never opened falls back to /offline.

The code is in example/offline-cache.

File upload

Uploads in chunks to disk, which can be paused, resumed, taken over by another tab, and continued after a reload or a restart of the server. Completed files can be downloaded. Upload and download rates have limits that the server enforces and every tab shows.

Features:

  • Per-tab state, an event addressed to 1 tab with datapages.SubjectStateID, and StreamClose, which releases the transfers of a closed tab. See Per-tab state and Events.
  • App.GETFile, a GET action that returns datapages.File, and its href builder. See Actions.
  • PUTChunk, an action that reads the request body and that JavaScript calls instead of Datastar.
  • enableBackgroundStreaming, which keeps the stream open while the tab is hidden. See Pages and routes.
  • Tests with net/http/httptest. See Testing.

Run:

go run ./cmd/server   # http://localhost:8080/
datapages watch       # http://localhost:7331/

The files go to uploads in the working directory, and -dir selects another directory.

The code is in example/file-upload.

Docs

A collaborative rich text editor. Any number of tabs edit the same document and see the changes, cursors and avatars of the others, and a tab keeps its changes across a reload or a lost connection. The editor is Quill in a Web Component. The server orders the changes with operational transformation of Quill deltas, ported to Go, and stores each document as a snapshot and a change log.

Features:

  • EventDocChanged, whose datapages.Subject field is bound to the signal docId, which reaches only the tabs of 1 document. See Events.
  • Per-tab state that records what a tab received, with StreamOpen and StreamClose. See Per-tab state.
  • sse.ExecuteScript, which hands the changes to the editor. See Actions.
  • App.GETImage, a GET action that serves uploaded images with datapages.File.
  • PageOffline, WithOffline and a self-hosted Datastar bundle. See Offline and shims.
  • A Web Component bundled by esbuild. See Templates and forms.
  • Go tests, and a JavaScript test that runs 3 editors against a model of the server. See Testing.

Run, with Node.js 24 or later for the editor bundle and its tests:

go run ./cmd/server   # http://localhost:8080/
make npm-install
make dev              # http://localhost:7331/
make test

The documents go to documents in the working directory, and -dir selects another directory. -host 0.0.0.0:8080 lets other devices on the network edit the documents.

The code is in example/docs.

See also