almostnojs
v1.3.0
Published
A minimalist, dependency-free JavaScript framework featuring tagged template rendering, DOM morphing, custom elements, state management, event handling, animations, and HTTP requests.
Downloads
44
Maintainers
Readme
AlmostNo.js
AlmostNo.js is a lightweight, zero-dependency JavaScript framework featuring tagged template rendering, DOM morphing, custom elements, reactive state management, chainable DOM manipulation, event handling, animations, and HTTP requests.
Features
- Tagged Template Rendering – Lit-style
htmltagged templates with surgical DOM updates. - DOM Morphing – Reconcile live DOM against new HTML without destroying state.
- Custom Elements – Reactive
AnJSElementbase class with batched updates and computed properties. - Tiny & Fast – 5 KB core, 6 KB extended, 12 KB full (minified + gzipped). Zero dependencies.
- Chainable API – Familiar
$().method()syntax for clean, readable code. - DOM Manipulation – Select, traverse, and modify elements effortlessly.
- Events & Event Bus – Attach, delegate, trigger events; cross-component communication.
- Reactive State – Proxy-based state with
onChange,onAny,patch, and DOM bindings. - Components – SSR-compatible server/client components with auto-mounting.
- HTTP Requests – Fetch wrappers with timeout handling and abort controllers.
- Animations – Simple CSS-based transitions.
- Utilities – Debounce, throttle, type checks, JSON parsing, and more.
Examples
See AlmostNo.js Live Examples in action.
- Animations
- Attributes
- Components
- Core Features
- DOM Manipulation
- Elements
- Events
- Filtering & Traversal
- HTTP Requests
- State Management
- Utilities
Browser Support
AlmostNo.js targets ES2020 and works on all modern browsers (Chrome, Firefox, Edge, Safari, Opera).
Installation
NPM
npm install almostnojsimport $, { html, render, morph, AnJSElement, registerComponent } from 'almostnojs';CDN
<!-- jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/almostnojs@latest/dist/cdn/almostno.full.js"></script>
<!-- UNPKG -->
<script src="https://unpkg.com/almostnojs@latest/dist/cdn/almostno.full.js"></script>Self-hosting
Download the latest release from dist/browser/ and include it directly:
<script src="./almostno.full.js"></script>Choosing the Right Version
Three prebuilt bundles are available, plus NPM with tree-shaking.
Feature Comparison
| Feature | Core | Extended | Full | NPM | |----------------------------|------|----------|------|-----| | DOM Manipulation | ✅ | ✅ | ✅ | ✅ | | Events & Event Bus | ✅ | ✅ | ✅ | ✅ | | Attributes | ✅ | ✅ | ✅ | ✅ | | HTTP Requests | ✅ | ✅ | ✅ | ✅ | | Animations | ❌ | ✅ | ✅ | ✅ | | Filtering & Traversal | ❌ | ✅ | ✅ | ✅ | | State Management | ❌ | ❌ | ✅ | ✅ | | Components | ❌ | ❌ | ✅ | ✅ | | Template Parts | ❌ | ❌ | ❌ | ✅ | | DOM Morphing | ❌ | ❌ | ❌ | ✅ | | Custom Elements | ❌ | ❌ | ❌ | ✅ |
Bundle Sizes (minified + gzipped)
| Version | Size | Path |
|-------------|---------|---------------------------------------|
| Core | ~5 KB | dist/browser/almostno.js |
| Extended| ~6 KB | dist/browser/almostno.extended.js |
| Full | ~12 KB | dist/browser/almostno.full.js |
Quick Start
Template Parts (Tagged Templates)
Render reactive templates with surgical DOM updates — only changed values are patched.
import { html, render } from 'almostnojs';
const app = document.getElementById('app');
function view(name) {
render(html`<h1>Hello, ${name}!</h1>`, app);
}
view('World'); // First render: creates DOM
view('AnJS'); // Update: patches only the text nodeAttributes
render(html`<div class="card ${active ? 'active' : ''}">
<button disabled=${!ready}>Submit</button>
</div>`, container);Lists
const items = ['Apple', 'Banana', 'Cherry'];
render(html`<ul>${items.map(i => html`<li>${i}</li>`)}</ul>`, container);Unsafe HTML
import { html, unsafeHTML, render } from 'almostnojs';
render(html`<div>${unsafeHTML('<em>trusted markup</em>')}</div>`, container);DOM Morphing
Reconcile live DOM against new HTML without destroying state, focus, or event listeners.
import { morph } from 'almostnojs';
morph(document.getElementById('app'), '<div class="updated">New content</div>');Custom Elements
Build reactive web components with AnJSElement.
import { AnJSElement, html, registerComponent } from 'almostnojs';
class MyCounter extends AnJSElement {
init() {
this.state.count = 0;
}
render() {
return html`
<button @click=${() => this.state.count++}>
Clicked ${this.state.count} times
</button>`;
}
}
registerComponent('my-counter', MyCounter);<my-counter></my-counter>Features: reactive state proxy, batched microtask updates, computed properties, observedAttributes reflection, init() / updated() / destroy() lifecycle hooks, auto-cleanup with this.own(), updateComplete promise, repeat() keyed lists.
Keyed Lists with repeat()
import { AnJSElement, html, repeat, registerComponent } from 'almostnojs';
class TodoList extends AnJSElement {
init() {
this.state.items = [
{ id: 1, text: 'Learn AnJS' },
{ id: 2, text: 'Build something' },
];
}
render() {
return html`<ul>${repeat(
this.state.items,
item => item.id,
item => html`<li>${item.text}</li>`
)}</ul>`;
}
}
registerComponent('todo-list', TodoList);Auto-Cleanup
class LiveWidget extends AnJSElement {
init() {
// Automatically unsubscribed when element disconnects
this.own($.listen('data:update', (data) => {
this.state.value = data;
}));
}
render() { return html`<span>${this.state.value}</span>`; }
}Awaiting Updates
const el = document.querySelector('my-counter');
el.state.count = 42;
await el.updateComplete;
// DOM is now updatedDOM Manipulation
$('div').text('Hello, World!');
$('#box').css('color', 'red').class('highlight');Events
$('#btn').on('click', () => alert('Clicked!'));
$.emit('app:ready', { ts: Date.now() });
$.listen('app:ready', data => console.log(data));State Management
const state = $('#app').state({ count: 0 });
$('#increment').on('click', () => state.count++);
$('#display').bind(state);<div id="app">
<span id="display" data-bind="count"></span>
<button id="increment">+1</button>
</div>Components
$.component("Card",
({ state, props }) => `
<div class="card">
<h3>${props.title}</h3>
<p>Likes: <span data-bind-this="likes"></span></p>
<button data-action="like">Like</button>
</div>`,
() => $.state({ likes: 0, like() { this.likes++ } })
);<Card title="Hello"></Card>HTTP Requests
$.get('/api/data').then(console.log);
$.post('/api/submit', { name: 'Jane' });
$.get('/api/slow', { timeout: 3000 });API Reference
Template Parts
| Function | Description |
|----------|-------------|
| html`...` | Tagged template literal — returns a TemplateResult |
| render(result, container) | Render a TemplateResult into a DOM element |
| clearTemplate(container) | Clear cached template data for a container |
| unsafeHTML(string) | Mark a string as trusted HTML (bypasses escaping) |
DOM Morphing
| Function | Description |
|----------|-------------|
| morph(target, newHTML) | Reconcile live DOM to match new HTML string |
Custom Elements
| Export | Description |
|--------|-------------|
| AnJSElement | Base class for reactive custom elements |
| registerComponent(name, cls) | Register a custom element (idempotent) |
| repeat(items, keyFn, templateFn) | Keyed list helper for efficient DOM reconciliation |
AnJSElement Instance API
| Member | Description |
|--------|-------------|
| state | Reactive proxy — property writes trigger batched updates |
| computed(name, deps, fn) | Define a computed property |
| render() | Return html`...` or a string — called on every update |
| update() | Force a synchronous DOM update |
| own(disposerFn) | Register a cleanup function — called automatically on disconnect |
| updateComplete | Promise that resolves after the current render cycle |
| static updateStrategy | 'microtask' (default) or 'raf' for frame-coalesced updates |
| init() | Lifecycle hook — called once after first render |
| updated() | Lifecycle hook — called after every render |
| destroy() | Lifecycle hook — called on disconnect before auto-cleanup |
Core
$(selector)– Select elements.$.extend(name, func, force)– Extend AlmostNo.js.
Iteration
.each(fn)– Iterate over matched elements..get(index)– Get an element by index..clone(deep)– Clone an element.
DOM Manipulation
.content(value, html)– Get/set text or HTML content..text(value)– Get/set text content..html(value)– Get/set HTML content..css(prop, value)– Get/set CSS styles..class(name, add)– Add, remove, or toggle classes..display(show)– Show or hide elements..hide()/.show()– Convenience hide/show..remove()– Remove elements from the DOM..empty()– Remove all child elements..insert(content, position)– Insert elements at a position..append(content)/.prepend(content)– Insert content at start/end..before(content)/.after(content)– Insert adjacent content..prop(name, value)– Get/set DOM properties..val(value)– Get/set form element values..focus()/.blur()– Focus and blur.
Attributes
.id(value)– Get/set theidattribute..attr(name, value)– Get/set attributes..removeAttr(name)– Remove an attribute..serialize()– Serialize a form.
Events
.on(event, selector?, handler)– Attach event listeners (optional delegation)..off(event, selector?, handler)– Remove event listeners..delegate(event, selector, handler)– Delegated event listener..undelegate(event, selector, handler)– Remove delegated listener..trigger(event)– Dispatch an event.
Event Bus
$.emit(event, data)– Emit a global event.$.listen(event, handler)– Listen for a global event.$.forget(event, handler)– Remove a global event listener.
Traversal
.next()/.prev()– Adjacent siblings..parent()– Parent element..children()– Direct children..siblings()– All siblings..closest(selector)– Closest matching ancestor.
Filtering
.filter(callbackOrSelector)– Filter elements..find(selector)– Find descendants..first()/.last()– First or last element..even()/.odd()– Even or odd indexed elements..has(className)– Check for a class.
Animations
.animate(styles, duration, easing)– Animate CSS properties..fade(opacity, duration)– Fade to a specific opacity..fadeIn(duration)/.fadeOut(duration)– Fade in/out.
State Management
.state(initialState)– Create a reactive state proxy..bind(state, context)– Bind state to DOM viadata-bind..unbind(state)– Remove bindings.$.global(name, initial)– Create or retrieve global state.$.hasGlobal(name)– Check if a global state exists.$.clearGlobal(name)– Remove a global state.
HTTP Requests
$.get(url, options)– GET request.$.post(url, data, options)– POST request.$.put(url, data, options)– PUT request.$.delete(url, options)– DELETE request.$.patch(url, data, options)– PATCH request.$.head(url, options)– HEAD request.$.options(url, options)– OPTIONS request.$.abortController()– Create an AbortController.
Utilities
$.json(string)– Safe JSON parse (returnsnullon failure).$.trim(string)– Trim whitespace.$.range(x, min, max)– Check if a number is within range.$.isFunction(v)/$.isObject(v)/$.isString(v)/$.isNumber(v)– Type checks.$.contains(parent, child)– Check DOM containment.$.debounce(fn, delay)– Debounced function.$.throttle(fn, limit)– Throttled function.$.element(tag, attrs, children)– Create an element.
Event Aliases
.click(cb)/.change(cb)/.submit(cb)/.keydown(cb)/.keyup(cb)/.mouseover(cb)/.mouseout(cb)– Event shortcuts.
Why AlmostNo.js?
- Modern & Minimal – No legacy baggage. ES2020 modules with tree-shaking.
- Tagged Templates – Lit-inspired rendering without a build step.
- DOM Morphing – Efficient reconciliation without virtual DOM overhead.
- Custom Elements – First-class web component support.
- Reactive State – Proxy-based reactivity with automatic DOM updates.
- Easy to Learn – Familiar jQuery-style API with modern capabilities.
- Fast & Lightweight – 5–12 KB gzipped depending on bundle.
- Extensible – Add custom methods, components, and global state.
License
This project is licensed under the MIT License — see the LICENSE file for details.
