MATES

Open Source

MATES

The JavaScript Framework for the Future

A lightweight, TypeScript-first framework with mutable state and blazing-fast DOM updates. No virtual DOM. No compiler. No JSX. 2× faster and 4× smaller than React, Built to handle Large Scale Applications

Measured, not claimed — see the benchmarks →

npm install mates

0
No Virtual DOM No compiler No JSX TypeScript First ~44KB Gzipped
M

Mutable State

Mutate state directly through setters. No reducers, no dispatch.

A

Actions

Trackable function utilities. Async, sync, cached, interceptable.

T

Templates

html`…` templates from mates. No JSX, no compiler, just JavaScript.

E

Events

Reactive event bus. Send messages anywhere within the app.

S

Setup Functions

Outer function runs once. Set up state, hooks, and logic cleanly.

Why Mates?

Everything you need to build production apps — nothing you don't

No Virtual DOM

Templates patch only the parts of the DOM that changed. Updates are surgical, not diffed from scratch. Much faster than React.

Two-Layer Components

Outer function runs once (setup). Inner function runs every render. Clear separation between initialization and reactivity.

Direct Mutations

No immutability gymnastics. Mutate state through setters or atom.set() and your views update automatically.

No Compiler, No JSX

Just tagged template literals — html, svg, directives, and more all export from mates. No separate lit-html install. Works in any TypeScript project out of the box.

TypeScript First

Every API is fully typed from the ground up. Amazing autocomplete, type inference, and compile-time error checking.

Scopes

Share state between parent and child components without prop drilling. Like React Context, but with plain classes and zero boilerplate.

Actions & Async

Track functions, intercept them, subscribe to results, handle loading/error states. Built-in async actions, task queues, and parallel task managers.

Lifecycle Hooks

onMount, onPaint, onCleanup, onAllMount, onError — intuitive hooks that run at the right time. No dependency arrays to manage.

~44KB Gzipped

One install covers the runtime and the batteries below. Optional packages (mates-virtual, mates-db, mates-ui) stay out of the core until you need them.

React vs Mates

Familiar syntax without JSX and immutable state. Just pure JavaScript template strings as HTML.

Mates vs React

Smaller ship size — and faster paints on a 100,000-item full DOM list. Toggle, add, and delete timed to the next frame.

Bundle size

KB gzip · lower is better

mates
44 KB
React stack
210 KB

mates is ~4.8× smaller (44 KB vs 210 KB)

  • react6
  • react-dom42
  • react-router-dom17
  • axios14
  • moment70
  • @emotion/react + styled14
  • @tanstack/react-query14
  • socket.io-client14
  • @reduxjs/toolkit14
  • react-redux5
100k todos — paint + DOM

100k full DOM · prod · ms · lower is better

Verify: Run mates bench · Run React bench · All frameworks

Load Build 100k-item list ~10.3×
Mates (raw components)
1,605 ms
mates
2,676 ms
React
16,557 ms
Toggle Complete one todo ~3.4×
Mates (raw components)
103 ms
mates
152 ms
React
351 ms
Add Append one todo ~2.4×
Mates (raw components)
175 ms
mates
255 ms
React
417 ms
Delete Remove one todo ~2.2×
Mates (raw components)
235 ms
mates
342 ms
React
517 ms
mates-ui vs MUI

KB gzip · icons excluded

Bundle size

mates-ui
156 KB
MUI Material
168 KB

mates-ui is ~1.08× lighter (156 KB vs 168 KB)

Features

mates-ui
29
MUI Material
21

mates-ui has more features than core MUI (29 vs 21; icons and charts excluded)

Sizes: @mui/material full import (~168 KB gzip, no @mui/icons-material); mates-ui production bundle with mates-icons contribution removed (~156 KB gzip). Features: high-level capability areas in each core package (icons and charts excluded). mates-ui ~29 vs @mui/material ~21 — date/time pickers, data grid, tree, chat, media, and similar live in mates-ui itself; MUI ships many of those only in MUI X. Raw component export counts are omitted because compound sub-parts and variants make them misleading.

Per-operation averages

Mean of two dual-round production runs. Mates uses guard on keyed `repeat` rows. Mates (raw components) uses `xRaw` + cloneNode rows.

Operation React mates Mates (raw) Ratio
Load 16,557 ms 2,676 ms 1,605 ms 10.3×
Toggle 351 ms 152 ms 103 ms 3.4×
Add 417 ms 255 ms 175 ms 2.4×
Delete 517 ms 342 ms 235 ms 2.2×

Bench: todo-100k-bench — production builds, full DOM list (no virtualization), Chrome. Time = state update → 2× requestAnimationFrame and DOM verification (data-todo-id probes). Times are means of two dual-round runs (load + 5× toggle/add/delete each), rounded. Mates uses repeat() keyed by id and guard() so unchanged row objects skip rebuilding. Mates (raw components) mounts an xRaw shell and patches rows with cloneNode (no repeat, no scheduler). React re-renders the list. Solid, Vue 3, and Angular 19.2 are on the Benchmarks page. Real apps at this scale usually virtualize.

Batteries included

Router, networking, dates, animations, and more ship in mates — about 44KB gzip for the whole toolkit. Add-ons stay optional.

Router

SPA routing with params, query/hash atoms, scroll restoration, and animatedRouter for enter/exit transitions.

Fetch utils

Typed HTTP helpers (Get/Post/Put/Patch/Delete), CSRF, interceptors, SSE streams, and wire-friendly error handling.

Date utils

Locale-aware calendars, timezones, formatting, and date math — no extra date library required.

Animation support

Keyframe presets, animateSwap, and animatedIf / animatedX for view transitions without a separate motion stack.

CSS-in-JS

stylesheet, themes, keyframes, and SSR-friendly style collection when you want styles next to components.

Portals & overlays

portal, popup, and dialog helpers with placement math for menus, modals, and floating UI.

WebSocket

First-party ws() helper for realtime connections with status tracking.

Forms & validation

formAtom plus validators (required, email, min/max, patterns) wired into reactive state.

Storage-backed atoms

Sync localStorage and sessionStorage into reactive atoms with LSAtom and SSAtom — including cross-tab updates.

Actions & async

action / asyncAction with interceptors, caching, polling, pagination helpers, and task queues.

DOM & lifecycle hooks

onMount, onPaint, onCleanup, plus window/scroll/visibility/keyboard helpers for app-level wiring.

Need virtual lists, IndexedDB, or document SSR? Reach for mates-virtual, mates-db, and mates-fullstack — installed only when you use them.

Browse the Docs

Every feature, hook, and utility — all in one place.

Browse the docs →

Edit the code — preview updates automatically

A full in-browser playground powered by mates-ide. Change the counter, tweak styles, or rewrite the whole app.

Open full playground →
import { html, atom, x, renderApp } from 'mates';

// Try editing this code — the preview updates live!

const Counter = () => {
const count = atom(0);

return () => html`
<div class="m-col m-items-center m-gap center">
<h1>${count()}</h1>
<div class="m-flex m-gap-sm">
<button class="btn-danger" @click=${() => count.set(n => n - 1)}>−</button>
<button class="btn-ghost" @click=${() => count.set(0)}>Reset</button>
<button class="btn-primary" @click=${() => count.set(n => n + 1)}>+</button>
</div>
</div>
`;
};

const App = () => {
return () => html`
<div class="m-col m-items-center m-gap-lg p-30 center">
<div>
<h1>Hello from Mates! 👋</h1>
<p class="muted">Edit this code — the preview updates live.</p>
</div>
${x(Counter)}
</div>
`;
};

renderApp(App, document.getElementById('app'));


Console
0 logs
No output yet — run your code to see logs here.

Ready to build something amazing?

Get started with Mates in under a minute.

npx create-mates my-app