toad.js

raw JSON →
0.3.4 verified Fri May 01 auth: no javascript

toad.js is a TypeScript GUI library for building desktop-style web applications using modern web technologies. Version 0.3.4 (March 2025) is in early development with weekly releases. It enforces a layered architecture (DDD/Clean Architecture) with Presentation Model pattern, focused on complex data-driven apps with large screens. Unlike React/Vue, it has no virtual DOM, no mobile support, and no eye candy — targeting pro users with consistent UIs. Requires Node >=21.7.1 and ESM only.

error Error [ERR_REQUIRE_ESM]: require() of ES Module /node_modules/toad.js/index.js from ... not supported.
cause Using require() instead of import.
fix
Change to dynamic import() or set type: module in package.json.
error TypeError: toad_js_1.TextModel is not a constructor
cause Importing TextModel from root instead of 'toad.js/model'.
fix
Change import to: import { TextModel } from 'toad.js/model';
error Error: Cannot find module 'toad.js/model'
cause Package not installed or import path misspelled.
fix
Ensure 'toad.js' is in package.json dependencies, and use correct case.
breaking ESM-only package — require() will throw ERR_REQUIRE_ESM
fix Use import syntax or dynamic import().
breaking Minimum Node.js version is 21.7.1 — older Node fails with engine check
fix Update Node to >=21.7.1.
gotcha Models and Views are in subpaths, not root package exports
fix Import from 'toad.js/model', 'toad.js/view', etc.
gotcha Package is pre-1.0 — API and import paths may change without semver major
fix Pin to exact version and test upgrades.
npm install toad.js
yarn add toad.js
pnpm add toad.js

Creates a minimal TOAD application with a counter button and label using View and Models.

import { Application, Button, Dialog, Label, NumberModel, TextModel } from 'toad.js';
import { View } from 'toad.js/view';

class MyView extends View {
  constructor() {
    super();
    this.count = new NumberModel(0);
    this.label = new TextModel('Hello, TOAD!');
  }

  render() {
    return `<div>
      <label>${this.label.value}</label>
      <button onclick="${this.onClick.bind(this)}">Count: ${this.count.value}</button>
    </div>`;
  }

  onClick() {
    this.count.value++;
    this.label.value = `Clicked ${this.count.value} times`;
  }
}

const app = new Application({
  view: new MyView(),
  title: 'TOAD Demo'
});
app.start();