A lightweight alternative to React in pure JavaScript (ES6+) with its own virtual DOM and philosophy of minimalism.
memo() blocks only the current component — children continue their own update chains independently, making optimization predictablewindow directly, without props drillingcontext: { key() { ... } }, children request values via this.context(key)init(props), memo(props), render({ title, items }) allow destructuring props right in the definitionnpm install tyaff
import { h, Component, mount } from 'tyaff';
const Counter = Component({
count: 0,
increment() {
this.update({ count: this.count + 1 });
},
render() {
return h('div', null,
h('p', null, 'Counter: ' + this.count),
h('button', { onClick: this.increment }, '+')
);
}
});
mount(Counter, document.getElementById('app'));
const ThemeProvider = Component({
theme: 'light',
context: {
theme() { return this.theme; },
toggleTheme() {
this.theme = this.theme === 'light' ? 'dark' : 'light';
this.update();
}
},
render() {
return h('div', null, this.props.children);
}
});
const ThemedButton = Component({
render() {
const theme = this.context('theme');
return h('button', { className: 'btn-' + theme }, 'Button');
}
});
mount(
h(ThemeProvider, null,
h(ThemedButton)
),
document.body
);
// store.js
export const store = { count: 0 };
// app.js
import { store } from './store.js';
import { h, Component, mount, refresh } from 'tyaff';
const Counter = Component({
render() {
return h('div', null, 'Count: ', store.count);
}
});
mount(Counter, document.getElementById('app'));
// Update
store.count = 55;
await refresh(); // all components will re-read the store
This project is a showcase of human-AI collaboration:
MIT