Fusor is a simple JavaScript library that helps create and update DOM elements.
It is:
- Simple ― two API methods:
create
&update
DOM - Concise ― less verbose than anything else
- Explicit ― what you see is what you get, no black box magic
- Flexible ― as using pure functions, both declarative and imperative
- Small/Performant ― size ~3kB, no dependencies
- W3C Standards Compliant
npm install @fusorjs/dom
Or:
- JSX boilerplate for: JavaScript or TypeScript
- CDN: https://esm.sh/@fusorjs/dom or https://cdn.skypack.dev/@fusorjs/dom
import {getElement, update} from '@fusorjs/dom';
import {section, div} from '@fusorjs/dom/html';
let count = 0;
const block = section(
{class: () => (count % 2 ? 'odd' : 'even')},
div('Seconds ', () => count, ' elapsed'),
div('Minutes ', () => Math.floor(count / 60), ' elapsed'),
);
document.body.append(getElement(block));
setInterval(() => {
count++;
update(block);
}, 1000);
Only tiny portions of the block
DOM tree are updated if they differ from the current values.
import {getElement, update} from '@fusorjs/dom';
let count = 0;
const block = (
<section class={() => (count % 2 ? 'odd' : 'even')}>
<div>Seconds {() => count} elapsed</div>
<div>Minutes {() => Math.floor(count / 60)} elapsed</div>
</section>
);
document.body.append(getElement(block));
setInterval(() => {
count++;
update(block);
}, 1000);
import {getElement, update} from '@fusorjs/dom';
import {section} from '@fusorjs/dom/html';
let count = 0;
const block = section(
{
id: 'set attribute or property automatically',
title_a: 'set attribute',
style_p: 'set property',
focus_e: () => 'set bubbling event handler',
blur_e_capture_once: () => 'set capturing event handler once',
// update dynamic values in this DOM node:
click_e_update: () => count++, // same as
click_e: () => {count++; update(block);}, // same as
click_e: (event, self) => {count++; update(self);},
class: count % 2 ? 'odd' : 'even', // static
class: () => (count % 2 ? 'odd' : 'even'), // dynamic
},
'Static child ', count, ' never changes.',
'Dynamic child ', () => count, ' is wrapped in a function.',
);
document.body.append(getElement(block));
import {getElement} from '@fusorjs/dom';
import {button, div} from '@fusorjs/dom/html';
const ClickCounter = (count = 0) =>
button({click_e_update: () => count++}, 'Clicked ', () => count, ' times');
const App = () => div(ClickCounter(), ClickCounter(22), ClickCounter(333));
document.body.append(getElement(App()));
import {getElement} from '@fusorjs/dom';
const ClickCounter = ({count = 0}) => (
<button click_e_update={() => count++}>Clicked {() => count} times</button>
);
const App = () => (
<div>
<ClickCounter />
<ClickCounter count={22} />
<ClickCounter count={333} />
</div>
);
document.body.append(getElement(<App />));
Components in both versions are interoperable.
import {getElement} from '@fusorjs/dom';
import {input, div} from '@fusorjs/dom/html';
const UppercaseInput = (value = '') =>
input({
value: () => value.toUpperCase(),
input_e_update: (event) => (value = event.target.value),
});
document.body.append(
getElement(
div(UppercaseInput(), UppercaseInput('two'), UppercaseInput('three')),
),
);
Your suggestions and contributions are always welcome!
Please see CONTRIBUTING for details and CHANGELOG for agenda.