Q.js
All-In-One Front-End Web Framework from Qbix, alternative to jQuery, Angular, Vue, Ember etc.
Install / Use
/learn @Qbix/Q.jsREADME
Q.js
All-In-One Front-End Web Framework from Qbix, alternative to jQuery, Angular, Vue etc.
Size: ~40KB (Minified + GZipped), compare to other frameworks
How to use: copy contents of dist into your project, and then include it like this:
| File Type | Code to Use |
|------------|-------------|
|.html files| <script type="module">import { Q } from 'https://unpkg.com/@qbixplatform/q.js@1.0.16/dist/Q.js</script>|
|.js or .ts files|import Q from 'https://unpkg.com/@qbixplatform/q.js@1.0.17/dist/Q.js';
|<img src="https://github.com/user-attachments/assets/ba3df93e-0cd8-4189-93fc-11947b63b684" alt="Description" width="100" height="87"> | Full documentation here: https://qbix.com/platform/guide/javascript |
This is part of the much larger full-stack Qbix Platform that contains many pre-built reusable tools, plugins, and requires PHP and Node.js on the back-end. If you want to build an entire full-stack social network like Facebook you're well-advised to go with that. But if you just want to use the lightweight front-end core, with your own back-end and other frameworks, then start with this framework here.
🌟 Advantages of Q.js vs other frameworks
1. No build step
React/Vue/Angular need bundlers, transpilers, tree-shakers, and hydration layers. Q.js works with plain .html and .js — drop it in and it runs.
2. Tiny footprint (~40KB gzipped)
Q.minimal.js is smaller than React (even without ReactDOM), Vue runtime, and far smaller than Angular. Yet it packs components, events, routing, caching, batching, i18n, animations, IndexedDB, service workers, and more — all in core.
3. Direct DOM updates (no Virtual DOM overhead)
No diffing, no reconciler. Q.js uses requestAnimationFrame and .rendering() hooks for high-performance, granular updates.
4. Autoloading methods & tools
Any method, template, or tool can be defined in its own file and is only loaded when first used. No code-splitting configs, no manual lazy-loading hacks — it’s automatic.
5. Tools = components + behaviors
Like React components or Vue directives, but attachable as behaviors to any DOM element. Multiple tools can live on the same element, making composition more flexible than “one component per node.”
6. Built-in batching & caching
APIs like Q.getter() and Q.batcher() deduplicate, throttle, and combine calls automatically. If multiple parts of the UI request the same object, it’s fetched once and everyone gets the result.
7. Templates that Just Work™
Use Handlebars, .html <template> files (Vue-style), or JS-defined templates. Designers can work in HTML, devs can work in JS — both paths integrate seamlessly.
8. First-class events & lifecycle
Events are observable, chainable (a.and(b), a.or(b), a.until(b)), and auto-clean up when a tool or page unloads. No more memory leaks or dangling listeners.
9. Progressive enhancement & SEO-friendly
Pages can render server-side HTML and Q.js simply activates tools as needed. No “blank page until hydration” problem — works with or without JS.
10. Unified, full-stack philosophy
It’s not just a front-end library. Q.js is part of the larger Qbix platform, which powers real social apps (with accounts, feeds, groups, payments, etc.). You can start small with Q.minimal.js, and later plug into the full stack without rewriting.
Q.js is smaller than jQuery, faster than React, easier than Vue, and more complete than Angular.
🔍 Features
Despite its size, Q.js implements many features not found in other front-end frameworks. Here is an overview of the main ones:
| Class Name | Description |
|------------|-------------|
| Q.Tool | reusable components, activate with Q.activate(element) |
| Q.Page | HTML pages, for your SPA, routes, browser history |
| Q.Event | events and handlers, loaded and unloaded automatically |
| Q.Template | for rendering templates, integrates with Handlebars |
| Q.Text | for loading internationalized translations and text for templates |
| Q.Method | defines methods loading JS files asynchronously as needed |
| Q.Visual | managing the front end interface, standard hints, as well as Q.Mask |
| Q.Animation | for animating using native Javascript animation |
| Q.Audio | speaking, loading and playing audio, etc. |
| Q.IndexedDB | for easy interaction with the built-in IndexedDB |
| Q.ServiceWorker | to manage service workers in a standard way |
| Requests | Q.request(), Q.handle(), Q.loadUrl(), Q.addScript(), Q.addStylesheet() |
| Flow | Q.chain(), Q.getter(), Q.batcher(), Q.promisify(), Q.debounce() |
| Helpers | Q.find(), Q.activate(), Q.cookie(), Q.handle() |
Overview
Main functionality
// Core
Q
.init(options)
.activate(element, options)
.replace(element, source)
.extend(target, ...sources)
.copy(object, fields, levels)
.exports(fn)
.require(src, callback)
.import(src)
.handle(eventOrURL, context, args)
// Events
Q.Event
.add(handler, key)
.set(handler, key)
.remove(key)
.removeAllHandlers()
.factory(name)
.and(otherEvent)
.or(otherEvent)
.until(otherEvent)
.then()
.filter(testFn)
.map(transformFn)
.debounce(ms)
.throttle(ms)
.queue(ms)
// Tools
Q.Tool
.define(name, constructor, defaults, methods)
.prepare(elementOrTag, toolName, options)
.remove(element)
.clear(container)
.onActivate(toolName)
// Pages
Q.Page
.onLoad(urlOrName)
.onUnload(urlOrName)
.push(url, options)
.pop()
.currentUrl
// Templates
Q.Template
.set(name, template, options)
.remove(name)
.compile(source, type, options)
.render(name, fields, callback, options)
.load(name, callback, options)
// Text / i18n
Q.Text
.setLanguage(lang, locale)
.set(name, data, options)
.get(name, callback, options)
.addFor(events, prefix, names)
.addedFor(event, name, options)
// Methods
Q.Method
.define(methods, namespace, closureFn)
.options
// Visual
Q.Visual
.intersection(a, b)
.scrollLeft()
.scrollTop()
.windowWidth()
.windowHeight()
.boundingRect(element, classFilter, includeHidden)
.getX(event, index)
.getY(event, index)
.shouldOpenInNewWindow(event)
// Animation
Q.Animation
.play(fn, options)
.pause()
.jump(timeOrFrame)
.rewind()
.nextFrame()
// Audio
Q.Audio
.play(src, options)
.pause(id)
.stop(id)
.speak(text, options)
// IndexedDB
Q.IndexedDB
.open(name, version, upgradeCallback)
.get(store, key)
.put(store, value)
.remove(store, key)
.clear(store)
// Service Workers
Q.ServiceWorker
.register(script, options)
.unregister(scope)
.message(handler)
// Requests
Q.request(url, slotName, callback, options)
Q.loadUrl(url, options)
Q.addScript(src, callback, options)
Q.addStylesheet(href, options)
Q.removeStylesheet(href)
Q.cookie(name, value, options)
// Flow
Q.chain(tasks, callback)
Q.getter(original, options)
Q.batcher(batchFn, options)
Q.promisify(fn, useThis, callbackIndex)
Q.debounce(fn, ms)
📝 Templates
You can dynamically create elements in a React-like way, such as this:
Q.element('div', {id: "foo", "class": "bar baz"}, [
Q.element('img', {src: "foo.png"}),
Q.element('img', {src: "bar.png"})
]);
Instead, you can define Handlebars templates like this:
Q.Template.set("Namespace/some/name", `put your template here`);
And then render them later like this:
Q.Template.render("Namespace/some/name").then(html => Q.replace(element, html));
Rendering templates that haven't been set yet causes requests to autoload from inside Q.Template.load.options.dir
🛠️ Tools
Tools represent re-usable components in Q.js -- just like in other front-end libraries, except Tools are only one part of a unified framework!
Here's how to define new types of Tools. Normally you'd define each one in its own file:
File: Namespace/js/tools/cool/name.js:
Q.Tool.define("Namespace/cool/name", constructor, defaultOptions, methods);
File: Namespace/js/tools/another.js:
Q.Tool.define("Namespace/another", function (options) {
this.refresh(); // call method of tool
}, {
x: 1,
y: 2
}, {
refresh: function () {
this.state; // copy of options
this.element; // the element it was activated on
this.renderTemplate('Namespace/another/view', this.state,
function (html, elements, tools) {
// now this.x and this.y point to elements from
// the template that was rendered, while
this.element.forEachTool('Namespace/cool/name', function () {
// run whenever a child tool activates
});
}, {
some: options,
'Namespace_cool_name_tool': {
some: childToolOptions
}
});
// this is how we handle in-place updates if x or y changes:
this.rendering([x, y], (changed, previous, timestamp) => {
Q.replace(this.elements.x, x); // very quick
Q.replace(this.elements.y, y); // very quick
this.element.addClass('updated_flash'); // some CSS effect
});
// to trigger these, anyone can simply call tool.stateChanged('x')
},
Q: {
onInit: function () {
// all child tools have been initialized
}
beforeRemove: function () {
// cleanup, but see Events section!
}
}
});
// define a template with a child tool
Q.Template.set("Namespace/another/view",
`<span class="Namespace_another_x">{{x}}</span>
<span class="Namespace_another_y">{{y}}</span>
{{{tool "Namespace/cool/name" "some-child-id" x=x y=3 z="foo"}}}`,
{
"elements": {
"x": ".Nam
