Documentation · v0.4.0

Build native apps with Tarve

Everything you need to ship a native Windows and Linux interface from Bun and TSX: setup, the rendering model and a reference page for each of the 95 built-in components.

Getting started

  1. Install

    Tarve needs Bun 1.4+ on Windows x64 or Linux x64.

    terminal
    bun add @tarve/core
    bun add -d typescript @types/bun
  2. Configure TypeScript

    Point the JSX runtime at @tarve/core.

    tsconfig.json
    {
      "compilerOptions": {
        "target": "ESNext",
        "module": "ESNext",
        "moduleResolution": "Bundler",
        "strict": true,
        "jsx": "react-jsx",
        "jsxImportSource": "@tarve/core",
        "types": ["bun", "@tarve/core/assets"]
      }
    }
  3. Write a window

    app.tsx
    import { Button, Column, Text, Window, createApp } from "@tarve/core";
    
    let count = 0;
    
    function App() {
      return (
        <Window title="Counter" width={520} height={360}>
          <Column flex={1} align="center" justify="center" gap={16}>
            <Text size={42} weight={700}>{count}</Text>
            <Button onClick={() => count++}>Increase</Button>
          </Column>
        </Window>
      );
    }
    
    const app = createApp(App);
    await app.ready;
    await app.closed;
  4. Run and ship

    terminal
    # runs the source directly, no build step
    bun app.tsx
    
    # Windows → .exe with the native runtime embedded
    bun run tarve build app.tsx --outfile dist/App.exe
    
    # cross-compile for Linux x64, no Rust toolchain needed
    bun run tarve build app.tsx --target linux-x64 --outfile dist/App

How rendering works

Your view is a plain function that returns TSX. Tarve compiles it into a retained tree, diffs it against the previous one and sends only the changed nodes to the native runtime, where Taffy lays them out and Vello, D3D11 or the CPU renderer paints them.

State can live in ordinary variables. When a native event handler such as onClick or onChange runs, Tarve schedules a re-render automatically. For changes that happen outside an event (timers, network responses, file watchers) call app.update() on the handle returned by createApp.

Controls are controlled: pass the current value (checked, value, open…) and update it in the matching on…Change callback. An idle window presents zero frames.

Components

Common props

Every component accepts these props in addition to its own.

PropTypeDefault
children

Content rendered inside the component.

Child—
highlight

Highlights text matches inside the node, as used by find-in-page.

TextHighlight—
id

Stable native node id. Used for focus, scrolling, tests and accessibility; popups derive their part ids from it.

string—
key

Reconciliation key that keeps list items stable between renders.

string | number—
motionFrom

Initial numeric values for a native enter transition.

MotionValues—
onHighlight

Reports how many highlight matches were found.

(event: { matchCount: number }) => void—
onPaste

Receives non-text clipboard content (files or a bitmap) pasted while focused.

(payload: PastePayload) => void—
onTransitionEnd

Called when a native transition finishes on a property.

(event: { property: MotionProperty }) => void—
rovingGroup

Joins a roving-focus group so arrow keys move focus between siblings.

boolean—
style

Layout, colour, border, shadow, gradient, transform and transition styles, plus hover/focus/active/disabled state styles.

Style—