ScopeDom is a Reactive DOM Orchestrator.
No Virtual DOM. No build step. Standard HTML attributes ($on-click, $if, $repeat) and text interpolation {{expression}} become reactive through native Web APIs via Proxies, WeakMaps, and MutationObservers.
- The DOM is the Source of Truth - No Virtual DOM layer. Your HTML is your application state.
- No Build Step - Plain JavaScript and HTML. No compiler. No transpiler. No bundler configuration.
- Declarative Reactivity - Expressions on real HTML elements and text.
$on-click,$if,$repeat,{{value}}. - Hierarchical Scopes -
$scopedeclares variable boundaries that walk up the DOM tree. Child elements inherit from their parent. - Immediate Observation - MutationObserver sees the elements as the DOM streams in. No DOMContentLoaded wait for functionality.
Pronounced similarly to "Kingdom"
- Deep Reactivity - Objects, Arrays, Maps, and Sets become reactive automatically. Infinite proxy depth, with WeakRefs preventing memory leaks.
- Hierarchical Scoping - Scope variables and methods cascade down the DOM tree. Both the
$scopeattribute and plugins create scoped contexts that child elements inherit from. - Zero Build - Plain HTML + JS. No compiler, no transpiler. Works from a single
<script>tag or import. - Plugin System - Injectable behaviour and custom attributes, with existing pre-made plugins:
$cloak,$parse,$if,$repeat
<!-- The data-scopedom-init attribute auto-activates the engine -->
<script src="scopedom.umd.js" data-scopedom-init></script>
<!-- Optional: Enable {{expression}} syntax via the parse plugin -->
<script src="parse.umd.js"></script>
<!-- The $scope attribute defines encapsulated scope variables -->
<div $scope="{ count: 0 }">
<!-- Use $parse:text to enable interpolation within text nodes -->
<p $parse:text>Count is: {{count}}</p>
<!-- Increment count on click event -->
<button $on-click="count++">Increment</button>
</div>WIP
Find everything you need to master ScopeDom:
WIP
| Feature | Status |
|---|---|
| Core Engine | 🧪 Experimental / PoC |
| Core Plugins | 🧪 Experimental |
| Commercial Use | ❌ Not Ready |
| Hobbyist Use | 🧪 Experimental |
| Unit Tests | 🚧 In Progress |
ScopeDom is currently in an experimental / proof-of-concept stage. It is intended for research and hobbyist use and is not yet ready for production environments.
- Infinite proxy depth - chained/nested values get their own
signalProxywith WeakRef references. - Method wrappers (
push,pop,splice) trigger updates on mutation. - Disable auto-proxification:
ScopeDom.init({ signalProxyAll: false })(signalProxyAll=trueby default). - Controller-level optional signal management even without
signalProxy. - Auto-Reactive:
cart.push({ name:'Milk', qty:2 });- reactivity fires automatically. Most standard prototypes are wrapped to auto-trigger signal reads & changes. - Deep Nesting:
settings.user.pref.theme = 'light';- The entire chain automatically usessignalProxy, no declarations per level. Every nested access creates its own signal on demand, so deeply nested objects get full reactivity with a single call.
- Designed to run with context of Scopes & Elements:
$scope,$scopeParent,$scopeTophelper variables$this,$parent,$previous,$next- DOM Elements & Navigation$eventon EventTarget listeners- Can return values, such as
{{expression}}&<div $if="count===1">
- Helper Methods:
$("#nav")(document),$$(".title")(element) - query selectors$on,$off,$emit- event registry for scopes & elements with native EventTarget
- Access variables directly, or as properties on scope helpers
$scope,$scopeParent,$scopeTop. - Variable lookups travel up the DOM tree:
<!-- Child scope inherits `user`+`ready` from parent, then defines local `firstName` -->
<div $scope="{ user:{ name:'Alice Johnson' }, ready:true }">
<span $scope="{ firstName:user.name.split(' ')[0] }" $parse:text>{{firstName}}: {{ready?'Ready':''}}</span>
</div>- Helper methods to queue computation tasks & render tasks.
- All DOM edits are done via
requestAnimationFrame. - All DOM references use
WeakMap/WeakSet/WeakRef.
$cloak- CSS cloak with anchor comment swapping, reducing/eliminating FOUC (Flash of Unstyled Content).$parse- Text interpolation{{expression}}and attribute binding.$if- Conditional rendering with match-case and sibling chains.$repeat- Data-driven element repetition/listing with identity-based DOM reconciliation &moveBefore.pipeExp- Expression pipes{{ item.price | $fmt.currency:'USD' }}live transformed to{{ $fmt.currency(item.price,'USD') }}.- Simple plugin hooks -
onConnect,onDisconnect,onPluginAdd,onExpression.
To submit a contribution, please create an issue or a pull request on the GitHub repository.
Note: Please ensure you run all existing tests after making any changes. All help, from code to documentation improvements, is greatly appreciated!
Copyright (c) 2026 Jason Sheppard @Jashepp.
All rights reserved. Licensing will transition to an open-source model once the project reaches a stable milestone.
Github Repository: https://github.com/Jashepp/ScopeDom