quell Light JS v1.0.0
quell-light.js is not a component library. It does not render anything. It does not manage state in the application sense. Its only mandate is behavioral stabilization: the small class of problems that CSS cannot solve safely on its own — runtime environment normalization, accessible attribute synchronization, modal focus isolation, and performant scroll tracking.
quell-light.js should feel like an extension of the browser’s own engine: invisible, unopinionated, and side-effect-free beyond its narrow contract
Overview & System Role
quell-light.js is the behavioral companion layer for the quell Light Architectural track.
It is intentionally not a component framework, rendering engine, state manager, virtual DOM abstraction, or UI runtime. Its responsibility is limited to the small set of browser behaviors that cannot be solved safely through CSS alone.
The file exists to provide:
- Runtime environment normalization
- Accessible disclosure state synchronization
- Modal focus containment and restoration
- Scroll-spy navigation tracking
The implementation is deliberately constrained by four architectural rules:
| Constraint | Description |
|---|---|
| Zero Dependencies | No third-party libraries, utilities, polyfills, or frameworks |
| Sovereign Implementation | Uses only native browser Is |
| Single Responsibility | Every module solves exactly one browser behavior problem |
| CSS Parity | JavaScript never becomes a second rendering system; CSS remains the visual source of truth |
The script behaves as an extension of the browser rather than an application runtime.
Module Architecture Matrix
| Module Name | Main Function Core | DOM Event Trapped | Target Elements Affected | Volume Context |
|---|---|---|---|---|
| Environment Normalize | measureScrollbarWidth(), initEnvironmentNormalization(), debounce(), |
resize, keydown | :root, <body> |
Volume I · Behavioral Foundations |
| Disclosures / UI Toggles | initDisclosureToggles(), handleToggleClick(), setToggleState(), closeSiblingsInGroup() |
click | [data-q-toggle], [data-q-active], [data-q-exclusive] |
Volume II · State Through Structure |
| Keyboard Focus Management | initFocusManagement(), watchDialogActivation(), activateTrap(), deactivateTrap(), handleFocusTrapKeydown(), handleEscapeKeydown(), handleDismissClick(), closeDialog() |
“keydown, click, MutationObserver mutations | <dialog>, [role=""dialog""], [role=""alertdialog""], [data-q-dismiss] |
Volume III · Advanced Interaction |
| Scroll Spy Tracking | initScrollSpy(), handleSpyIntersections(), activateSpyLink() |
IntersectionObserver threshold crossings | [data-q-spy], [data-q-spy-link] |
Volume III · Advanced Interaction |
Internal Utility Layer
The Internal Utility Layer provides lightweight, dependency-free foundational helpers required by the high-level behavior modules. These utilities operate quietly behind the runtime environment, ensuring visibility-aware focus tracking and performant execution boundaries without leaking into the public API surface.
Utility Architecture Matrix
| Utility Name | Parameters | Internal State | Primary Consumer | Architectural Purpose |
|---|---|---|---|---|
getFocusableChildren |
root (Element) |
None | Module 3: Keyboard Focus Management | Constructs a visibility-aware snapshot of keyboard-reachable DOM nodes, filtering out hidden or inert elements to guarantee strict ARIA containment compliance. |
debounce |
fn (Function), wait (Number) |
timer (Identifier) |
Module 1: Environment Normalization | Restricts execution frequency of layout-heavy paint measurements during continuous, erratic browser window resize cycles. |
Function: getFocusableChildren(root)
Contract
function getFocusableChildren(root)
Returns an ordered array of focusable descendants.
Included Selectors
a[href]
area[href]
button:not([disabled])
input:not([disabled]):not([type="hidden"])
select:not([disabled])
textarea:not([disabled])
details > summary:first-of-type
[tabindex]:not([tabindex="-1"])
audio[controls]
video[controls]
[contenteditable]:not([contenteditable="false"])
Filtering Rules
Excluded when:
hidden === trueInside ancestor [hidden]display: nonevisibility: hidden
Rationale
Focus management must reflect actual keyboard reachability rather than DOM presence. The function creates a visibility-aware focus model suitable for accessibility enforcement.
Function: debounce(fn, wait)
Contract
function debounce(fn, wait)
Internal timer-based debounce utility.
State
let timer;
Usage
Only used for scrollbar-width recalculation during resize.
Rationale
Avoids repeated layout work during continuous viewport resizing.
Module 1 — Environment Normalization
API Snippet & Contract
State
let _lastViewportWidth = -1;
Functions
function measureScrollbarWidth()
function initEnvironmentNormalization()
Runtime Measurements
window.innerWidth
document.documentElement.clientWidth
CSS Variable Output
--q-scrollbar-width
Applied through:
document.documentElement.style.setProperty(
'--q-scrollbar-width',
`${scrollbarWidth}px`
);
Events Registered
Resize
window.addEventListener(
'resize',
debounce(measureScrollbarWidth, 150),
{ passive: true }
);
Keyboard Detection
window.addEventListener(
'keydown',
handleFirstTabKeypress
);
Keyboard Modality State
On first:
Tab
keypress:
document.body.setAttribute(
'data-q-keyboard',
'true'
);
Listener then removes itself.
Failsafe & Edge Cases Handled
Overlay Scrollbars
Math.max(0, delta)
Prevents negative widths.
Duplicate Measurements
Viewport width caching prevents unnecessary recalculation.
Passive Resize Handling
Ensures browser compositing is never blocked.
One-Time Keyboard Detection
Listener self-destructs after first successful detection.
Rationale
Environment normalization solves the browser-state problems CSS cannot independently measure.
The module exposes information to CSS rather than styling elements directly. JavaScript computes; CSS decides presentation.
Module 2 — Disclosures / UI Toggles
API Snippet & Contract
Functions
function initDisclosureToggles()
function handleToggleClick(event)
function setToggleState(trigger, targetEl, open)
function closeSiblingsInGroup(group, activeTrigger)
Delegated Event
document.body.addEventListener(
'click',
handleToggleClick
);
Trigger Attribute
data-q-toggle="target-id"
Target Resolution
document.getElementById(targetId)
Trigger State
aria-expanded="true"
aria-expanded="false"
Target State
Open:
data-q-active
Closed:
data-q-active removed
Exclusive Group Mechanics
Container:
data-q-exclusive
Lookup:
trigger.closest('[data-q-exclusive]')
Sibling Search:
group.querySelectorAll('[data-q-toggle]')
Behavior:
- Active sibling remains open
- Other expanded siblings close
- Nested exclusive groups remain isolated
Failsafe & Edge Cases Handled
Missing Target ID
if (!targetId) return;
Missing DOM Target
console.warn(
`[Quell] data-q-toggle target not found: #${targetId}`
);
Execution continues safely.
Nested SVG/Icon Clicks
Uses:
event.target.closest('[data-q-toggle]')
to resolve trigger ownership correctly.
Rationale
Disclosure state is centralized into a single delegated listener.
This provides:
- Dynamic DOM compatibility
- Constant listener overhead
- Consistent ARIA synchronization
- No per-component initialization
Module 3 — Keyboard Focus Management
API Snippet & Contract
Internal State
let _activeDialogEl = null;
Opener Registry
const _dialogOpenerMap = new WeakMap();
Functions
function initFocusManagement()
function watchDialogActivation()
function activateTrap(dialogEl)
function deactivateTrap(dialogEl)
function handleFocusTrapKeydown(event)
function handleEscapeKeydown(event)
function handleDismissClick(event)
function closeDialog(dialogEl)
Events Registered
Focus Trap
document.addEventListener(
'keydown',
handleFocusTrapKeydown
);
Escape Dismiss
document.addEventListener(
'keydown',
handleEscapeKeydown
);
Dismiss Trigger
document.body.addEventListener(
'click',
handleDismissClick
);
MutationObserver Contract
Observed Attribute:
data-q-active
Observer Configuration:
{
subtree: true,
attributes: true,
attributeFilter: ['data-q-active']
}
Dialog Types Accepted:
<dialog>
role="dialog"
role="alertdialog"
Focus Trap Mechanics
Focus Snapshot
getFocusableChildren(_activeDialogEl)
Tab Wrapping
Forward:
last -> first
Backward:
first -> last
Empty Dialog Handling
If no focusable elements exist:
event.preventDefault()
Focus cannot escape.
Activation Strategy
Priority Order:
1
[autofocus]
2
First focusable descendant
3
Dialog container
Focus Restoration
Stored:
_dialogOpenerMap.set(
dialogEl,
currentFocus
);
Restored:
opener.focus({
preventScroll: true
});
Dismiss Mechanics
Trigger:
data-q-dismiss
Ancestor Search:
dialog,
[role="dialog"],
[role="alertdialog"]
Native Dialog Integration
Open:
showModal()
Close:
close()
Both guarded for safe execution.
Failsafe & Edge Cases Handled
No Active Dialog
Immediate return.
Missing Dialog Ancestor
Warning issued.
Dialog Removed From DOM
WeakMap prevents memory leaks.
Already Open Native Dialog
showModal() exceptions safely ignored.
Focus Return Validation
document.contains(opener)
verified before focus restoration.
Rationale
This module enforces WCAG-compliant modal behavior while remaining independent from visual implementation.
Focus containment, opener tracking, and return-focus logic are implemented as browser-level behavioral guarantees rather than component-level assumptions.
Module 4 — Scroll Spy Tracking
API Snippet & Contract
State
let _spyRootMargin = '-10% 0px -10% 0px';
const _spyRatioCache = new Map();
Functions
function initScrollSpy()
function handleSpyIntersections(entries)
function activateSpyLink(activeId)
Observer Configuration
new IntersectionObserver(
handleSpyIntersections,
{
root: null,
rootMargin: _spyRootMargin,
threshold: [0, 0.4]
}
);
Observed Elements
Sections:
data-q-spy="section-id"
Navigation Links:
data-q-spy-link="section-id"
Ratio Cache
Stores:
Map<Element, number>
Purpose:
- Avoid repeated DOM lookups
- Maintain state between observer batches
- Preserve ratios for unchanged sections
Activation Threshold
0.4
Minimum visibility required:
40%
Active Link State
Activated:
data-q-current="true"
aria-current="location"
Deactivated:
data-q-current removed
aria-current removed
Failsafe & Edge Cases Handled
No Spy Targets
Initialization exits immediately.
Multiple Visible Sections
Highest ratio wins.
No Valid Section
All active states cleared.
Rationale
Scroll tracking is delegated entirely to browser-native visibility observation.
No:
- Scroll listeners
- requestAnimationFrame polling
- getBoundingClientRect loops
This produces scalable navigation awareness with minimal runtime overhead.
Specificity & State Control Mechanics
A defining architectural principle of Quell Light is that JavaScript never becomes a styling engine.
CSS State Channels
Environment
--q-scrollbar-width
Disclosure Open State
data-q-active
Disclosure Accessibility State
aria-expanded="true|false"
Scroll Spy Current State
data-q-current="true"
Scroll Spy Accessibility State
aria-current="location"
Dialog Open State
data-q-active
No module injects inline visibility styles, dimensions, positioning rules, colors, spacing values, transforms, animations, or layout directives.
JavaScript emits state.
CSS interprets state.
Public API Surface
A defining architectural principle of quell Light is that JavaScript never becomes a styling engine.
CSS State Channels
Environment
--q-scrollbar-width
Disclosure Open State
data-q-active
Disclosure Accessibility State
aria-expanded="true|false"
Scroll Spy Current State
data-q-current="true"
Scroll Spy Accessibility State
aria-current="location"
Dialog Open State
data-q-active
No module injects inline visibility styles, dimensions, positioning rules, colors, spacing values, transforms, animations, or layout directives.
JavaScript emits state.
CSS interprets state.
Initialization
quell.init()
Protected by:
let _initialized = false;
Duplicate calls:
console.warn(...)
and safely exit.
Dialog Control
quell.openDialog(elOrId)
quell.closeDialog(elOrId)
Accepted:
Element
or
String ID
Scroll Spy Configuration
quell.setSpyRootMargin(margin)
Updates:
_spyRootMargin
Teardown
quell.destroy()
Removes:
- Toggle click listener
- Dismiss click listener
- Focus trap listener
- Escape listener
Resets:
_initialized
_activeDialogEl
_lastViewportWidth
_spyRatioCache
Known v1 limitation:
- Observer instances are not retained for disconnect()
Auto Initialization Contract
Disabled Through:
<script>
window.__quellNoAutoInit = true;
</script>
Auto-init Path:
DOMContentLoaded
Already-loaded DOM Path:
quell.init()
called synchronously.
Key Architectural Decisions
- Native browser APIs are preferred over abstractions.
- Event delegation minimizes listener count and supports dynamic DOM injection.
- MutationObserver decouples focus management from disclosure mechanics.
- WeakMap prevents dialog opener memory leaks.
- IntersectionObserver eliminates scroll-event polling.
- ARIA attributes serve as the accessibility source of truth.
- CSS custom properties expose environment measurements without style injection.
- State is represented through attributes rather than imperative styling.
- Focus restoration follows ARIA Authoring Practices guidance.
- Scroll-spy maintains a single-current-link model.
- Modal containment enforces WCAG keyboard accessibility expectations.
- Initialization is idempotent and protected from double bootstrapping.
- Behavioral parity is maintained with the Quell CSS architecture rather than creating an independent runtime layer.
- The framework remains dependency-free, sovereign, portable, and browser-native.
Quell Design Summary
quell Light treats JavaScript as a behavioral stabilizer, not a rendering authority. The browser remains the platform, CSS remains the layout engine, ARIA remains the accessibility contract, and JavaScript supplies only the runtime intelligence required to bridge the gaps that CSS cannot safely solve alone.
© 2026 Ortiz Design Studio. | quell system documentation.