
Security News
Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
@eirikb/domdom
Advanced tools
The proactive web front-end framework for the unprofessional
Facts - not highlights, just facts:
domdom has full support for Deno!
See https://github.com/eirikb/domdom-deno and https://deno.land/x/domdom .
Install:
npm i @eirikb/domdom
run.sh:
npx parcel index.html
<body>
<script type="module" src="app.tsx"></script>
</body>
import domdom from '@eirikb/domdom';
const { React, init } = domdom({});
const view = <div>Hello, world!</div>;
init(document.body, view);
Output:
All elements created with tsx are elements which can be instantly referenced.
const element = <span>Hello, world :)</span>;
element.style.color = 'red';
Output:
By creating a function you create a Domponent (component).
const Button = () => <button>I am button!</button>;
const view = (
<div>
<Button />
</div>
);
Output:
It's possible to pass in children, and get a callback when a domponent is mounted (in DOM).
All attributes are passed in first argument.
const Button = ({ color }: { color: string }, { mounted, children }: Opts) => {
const button = <button>Hello {children}</button>;
mounted(() => (button.style.color = color));
return button;
};
const view = (
<div>
<Button color="blue">World!</Button>
</div>
);
Output:
All attributes starting with 'on' are added to addEventListener on the element.
const view = (
<button
onClick={(event: Event) => {
event.target.style.color = 'red';
}}
>
Click me!
</button>
);
Output:
State handling in domdom is simple: No local state, only one huge global state.
Setting data directly on the data
object can update DOM directly in combination with don
interface Data {
hello: string;
}
const { React, init, don, path } = domdom<Data>({
hello: 'World!',
});
const view = <span>{don(path().hello)}</span>;
Output:
interface User {
name: string;
}
interface Data {
users: User[];
}
const { React, init, don, path } = domdom<Data>({
users: [{ name: 'Hello' }, { name: 'World' }],
});
const view = (
<ul>
{don(path().users.$).map(user => (
<li>{user.name}</li>
))}
</ul>
);
Output:
interface User {
name: string;
}
interface Data {
users: User[];
}
const { React, init, don, data, path } = domdom<Data>({
users: [{ name: 'Hello' }, { name: 'World' }, { name: 'Yup' }],
});
const view = (
<div>
<ul>
{don(path().users.$).map(user => (
<li>{don(path(user).name)}</li>
))}
</ul>
<button onClick={() => (data.users[1].name = '🤷')}>Click me!</button>
</div>
);
Output:
interface Data {
hello: string;
}
const { React, init, don, path, data } = domdom<Data>({
hello: 'World!',
});
const view = (
<div>
<div>A: Hello, {data.hello}</div>
<div>B: Hello, {don(path().hello)}</div>
<div>
<button onClick={() => (data.hello = 'there!')}>Click me!</button>
</div>
</div>
);
Output:
interface Data {
toggle: boolean;
}
const { React, init, don, path, data } = domdom<Data>({
toggle: false,
});
const view = (
<div>
<button onClick={() => (data.toggle = !data.toggle)}>Toggle</button>
<button disabled={don(path().toggle)}>A</button>
<button disabled={don(path().toggle).map(res => !res)}>B</button>
</div>
);
Output:
interface Data {
hello: string;
}
const { React, init, don, path } = domdom<Data>({
hello: 'World!',
});
const view = (
<div>
<div>Hello, {don(path().hello)}</div>
<div>
<input type="text" bind="hello" />
</div>
</div>
);
Output:
Aggregate data. Supports:
map
sort
slice
filter
And in addition accompanying "on" version, making it possible to listen for an external path:
mapOn
sortOn
sliceOn
filterOn
interface User {
name: string;
}
interface Data {
users: User[];
}
const { React, init, don, path } = domdom<Data>({
users: [{ name: 'Yup' }, { name: 'World' }, { name: 'Hello' }],
});
const view = (
<ul>
{don(path().users.$)
.filter(user => user.name !== 'World')
.sort((a, b) => a.name.localeCompare(b.name))
.map(user => (
<li>{user.name}</li>
))}
</ul>
);
Output:
How to handle common tasks with domdom
import domdom from '@eirikb/domdom';
type Route = 'panel-a' | 'panel-b';
interface Data {
route: Route;
}
const { React, init, don, path, data } = domdom<Data>({ route: 'panel-a' });
const PanelA = () => (
<div>
Panel A :) <button onclick={() => gotoRoute('panel-b')}>Next panel</button>
</div>
);
const PanelB = () => <div>Panel B! (hash is: {window.location.hash})</div>;
const view = (
<div>
{don(path().route).map((route: Route) => {
switch (route) {
case 'panel-b':
return <PanelB />;
default:
return <PanelA />;
}
})}
</div>
);
function gotoRoute(route: Route) {
window.location.hash = route;
}
window.addEventListener(
'hashchange',
() => (data.route = window.location.hash.slice(1) as Route)
);
init(document.body, view);
Output:
This is how I would suggest putting domdom in its own file for importing.
import { data, don, init, path, React } from './domdom';
const view = <div>Hello, {don(path().hello)}</div>;
data.hello = 'There :)';
init(document.body, view);
import domdom from '@eirikb/domdom';
export interface Data {
hello: string;
}
const dd = domdom<Data>({ hello: 'world' });
export const React = dd.React;
export const init = dd.init;
export const data = dd.data;
export const don = dd.don;
export const path = dd.path;
Output:
At writing moment domdom doesn't have any unmount callback. I'm not a big fan of destructors, unmounted, dispose or similar. This might seem silly, and it might not be obvious how to use say setInterval, without this preventing the element from ever being cleaned up by garbage collector.
This is how I would suggest putting domdom in its own file for importing.
import domdom from '@eirikb/domdom';
interface Data {
run: boolean;
tick: number;
}
const { React, init, don, path, data } = domdom<Data>({
run: false,
tick: 0,
});
const view = (
<div>
<img
src="https://i.imgur.com/rsD0RUq.jpg"
style={don(path().tick).map(tick => ({ rotate: `${tick % 180}deg` }))}
/>
<button onClick={() => (data.run = !data.run)}>Start/Stop</button>
</div>
);
(function loop(time) {
if (data.run) {
data.tick = time;
}
requestAnimationFrame(loop);
})(0);
init(document.body, view);
FAQs
The proactive web front-end framework for the unprofessional
The npm package @eirikb/domdom receives a total of 3 weekly downloads. As such, @eirikb/domdom popularity was classified as not popular.
We found that @eirikb/domdom demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
Security News
React's CRA deprecation announcement sparked community criticism over framework recommendations, leading to quick updates acknowledging build tools like Vite as valid alternatives.
Security News
Ransomware payment rates hit an all-time low in 2024 as law enforcement crackdowns, stronger defenses, and shifting policies make attacks riskier and less profitable.