G
YouTube TikTok Games
Documentation · v0.12.0

Tarve documentation

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 97 built-in components.

Getting started

  1. Install

    Tarve needs Bun 1.4+ (or Node.js 26.10+) on Windows x64 or Linux x64. From there you also build for Android.

    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.

For values that change many times a second (a clock, a progress bar, an animation), use a signal(). Passed as a text child or a style value, it is bound to that node: setting count.value sends only that field to the native runtime, with no render, diff or layout when the size stays the same. batch() groups several changes into one update, and <audio time={position}> writes the playback position into a signal.

clock.tsx
import { Text, Window, createApp, signal } from "@tarve/core";

const time = signal(new Date().toLocaleTimeString());
setInterval(() => { time.value = new Date().toLocaleTimeString(); }, 1000);

createApp(() => (
  <Window title="Clock">
    <Text size={48}>{time}</Text>
  </Window>
));

<Scroll followTail> keeps a chat or a log at its end while content grows, until the user scrolls away; app.scrollTo(id, { y: "end", smooth: true }) scrolls a Scroll after the next layout.

Style anything with the style prop or with Tailwind classes: class="flex gap-2 p-4 hover:bg-muted" compiles to the same native style, with no CSS involved.

Components

Common props

Every component accepts these props in addition to its own.

PropTypeDefault
children

Content rendered inside the component.

Child—
class

Same as `className`, HTML spelling. Both may be given; `className` comes last.

string—
className

Tailwind utility classes, compiled to `style` at the call site; an explicit `style` wins.

string—
draggable boolean—
dropTarget boolean—
fileDropTarget boolean—
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—
onDragEnd (event: DragEndEvent) => void—
onDragEnter (source: string) => void—
onDragLeave (source: string) => void—
onDragMove (event: DragMoveEvent) => void—
onDragStart (position: DragPosition) => void—
onDrop (event: DropEvent) => void—
onFileDragEnter

Files entered the node; `paths` are the dragged files.

(paths: string[]) => void—
onFileDragLeave () => void—
onFileDrop (event: FileDropEvent) => void—
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—
onPointerLeave

The pointer left this node and its children (DOM `pointerleave`).

() => void—
onPointerMove

Pointer position inside this node (like DOM `offsetX`/`offsetY`) while it is over it or its children.

(point: { x: number; y: number }) => void—
onSize

Content-box size after layout, on mount and whenever it changes (a ResizeObserver).

(size: { width: number; height: number }) => 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—