Skip to content
F
GitHubLight theme

Getting started

Pick where you render

FlowView is pre-1.0. Every npm command below installs a published package. Requires Node.js 22.12 or newer for the JavaScript tooling.

Astro

Supports Astro 5, 6 and 7. Embed templates in .astro files, or import standalone.flow files.

  1. 1. Install

    sh
    npm install @flowview/astro @flowview/runtime
  2. 2. Configure

    js
    // astro.config.mjs
    import { defineConfig } from "astro/config";
    import flowview from "@flowview/astro";
    
    export default defineConfig({
      integrations: [flowview()],
    });
  3. 3. Write a template

    astro
    <template flowview={context} is:raw>
      @if (context.user) {
        <h1>Hello {{ context.user.name }}</h1>
      }
    </template>
Add Events to Astro
sh
npm install @flowview/astro-events @flowview/events @flowview/vite-events
js
// astro.config.mjs
import { defineConfig } from "astro/config";
import flowview from "@flowview/astro";
import flowviewEvents from "@flowview/astro-events";

export default defineConfig({
  integrations: [flowviewEvents(), flowview()],
});

Then write (click)="save()" in a template and declare save in one<script data-flowview> block. See Events →

Vite, Hono, Node.js and Workers

Supports Vite 6, 7 and 8. A .flow import is a module exportingrender(context). Your server decides when to call it.

  1. 1. Install

    sh
    npm install @flowview/vite @flowview/runtime
  2. 2. Configure

    ts
    // vite.config.ts
    import { defineConfig } from "vite";
    import flowview from "@flowview/vite";
    
    export default defineConfig({
      plugins: [flowview()],
    });
  3. 3. Render from a route

    Honots
    import { render } from "./users.flow";
    
    app.get("/users", async (c) => {
      return c.html(render({ users: await getUsers() }));
    });
  4. Or from a Worker

    Cloudflare Workersts
    import { render } from "./page.flow";
    
    export default {
      async fetch() {
        return new Response(render({ title: "Hello" }), {
          headers: { "Content-Type": "text/html; charset=utf-8" },
        });
      },
    };
Add Events to Vite
sh
npm install @flowview/vite-events @flowview/events
ts
// vite.config.ts
import { defineConfig } from "vite";
import flowview from "@flowview/vite";
import flowviewEvents from "@flowview/vite-events";

export default defineConfig({
  // Events must run before the HTML compiler sees the template.
  plugins: [flowviewEvents(), flowview()],
});

The <script data-flowview> block is served as a virtual module, so your client entry must import it, and your server must emit that script tag. The repository's Hono example shows the full wiring.

TypeScript: add "types": ["@flowview/vite/client"] to import .flow files.

Browser DOM

For a small client-side UI, compile a .flow file with Vite or Astro and mount it with@flowview/dom. Each update() replaces the target's HTML. State is yours to manage;@flowview/reactive is optional.

  1. 1. Install

    sh
    npm install @flowview/dom @flowview/vite @flowview/runtime

    2. Template

    items.flowflow
    <ul>
      @for (item of context.items; track item.id) {
        <li [class.done]="item.done">{{ item.name }}</li>
      } @empty {
        <li>Nothing yet</li>
      }
    </ul>
  2. 3. Mount and update

    ts
    import { createView } from "@flowview/dom";
    import { render } from "./items.flow";
    
    const view = createView("#app", render);
    
    view.render({ items: [] });
    view.update({ items: [{ id: 1, name: "Ship it" }] });

    4. Optional state

    ts
    import { createView } from "@flowview/dom";
    import { effect, signal } from "@flowview/reactive";
    import { render } from "./items.flow";
    
    const state = signal({ loading: false, items: [] });
    const view = createView("#app", render);
    
    // The one explicit boundary: state -> view.
    effect(() => {
      view.update(state());
    });

See the working example →

Native Rust static rendering

Render templates to HTML from Rust with no Node.js, browser or JavaScript engine. The context is JSON, and templates use a deterministic expression subset (property paths, literals, comparisons and boolean operators). Function calls are rejected with a diagnostic.

Add the crate

sh
# Not yet published on crates.io; depend on the Git repository.
cargo add --git https://github.com/Andersseen/flowview flowview-compiler
cargo add serde_json

flowview-compiler is not yet published on crates.io, so the command above uses the Git repository.

Compile once, render many

rust
use flowview_compiler::{compile_static, StaticCompileOptions};

let template = compile_static(source, StaticCompileOptions::default())?;

for page in &pages {
    let context = serde_json::to_value(page)?;
    let html = template.render(&context)?;
    // write html ...
}

Prefer the command line? Build the CLI from the repository and runflowview compile page.flow --target static-html --data context.json. See theRust embedding guide.

Next