Skip to content

Instantly share code, notes, and snippets.

@Kcko
Last active June 18, 2025 11:19
Show Gist options
  • Save Kcko/199421a29ceb6c1fffd1137a44f18e9d to your computer and use it in GitHub Desktop.
Save Kcko/199421a29ceb6c1fffd1137a44f18e9d to your computer and use it in GitHub Desktop.
// Pattern 1 — Bind Helper
export function S(selector) {
const nodes = document.querySelectorAll(selector);
nodes.forEach(bindAll); // Bind helpers to node(s)
return nodes.length > 1 ? nodes : nodes[0]; // native node(s) returned
}
export function C(tag) {
const node = document.createElement(tag);
return bindAll(node); // Bind helpers to node(s)
}
function bindAll(node) {
node.addClass = addClass.bind(node);
node.attr = attr.bind(node);
return node;
}
//--- Extension functions ---//
function addClass(...cls) {
this.classList.add(...cls);
return this;
}
function attr(key, val) {
if (val !== undefined) {
this.setAttribute(key, val);
return this;
}
return this.getAttribute(key);
}
// Usage:
import { S, C } from './helper.js';
const btn = C('button').addClass('btn', 'primary').attr('type', 'submit');
btn.click(); // native method
S('.card').forEach(el => el.addClass('highlight').attr('data-live', '1'));
// Pattern 2 — Prototype Boost
export const S = document.querySelectorAll; // Select alias
export const C = document.createElement; // Create alias
const helpers = {
addClass(...cls) {
this.classList.add(...cls);
return this; // keep it chainable
},
attr(key, val) {
if (val !== undefined) {
this.setAttribute(key, val);
return this; // keep it chainable
}
return this.getAttribute(key);
}
};
// Bind helpers to prototype
for (const [name, fn] of Object.entries(helpers)) {
if (!(name in HTMLElement.prototype)) {
Object.defineProperty(HTMLElement.prototype, name, {
value: fn,
writable: false,
configurable: true,
enumerable: false // not to show in for-in loops
});
}
}
// usage same as 1
// Pattern 3 — Mini Wrapper (“DIY jQuery”)
class Q {
constructor(sel) {
if (typeof sel === 'string') {
this.nodes = [...document.querySelectorAll(sel)];
} else if (sel instanceof Node) {
this.nodes = [sel];
} else {
this.nodes = [...sel]; // assume NodeList, HTMLCollection or Array
}
}
/* shared helpers — ONE copy in memory */
addClass(...cls) {
this.nodes.forEach(n => n.classList.add(...cls));
return this;
}
attr(key, val) {
if (val !== undefined) {
this.nodes.forEach(n => n.setAttribute(key, val));
return this;
}
return this.nodes[0]?.getAttribute(key);
}
/* helpers to exit the wrapper */
get(idx = 0) { return this.nodes[idx]; }
all() { return this.nodes; }
append(child) {
const isNode = child instanceof Node;
const node = isNode ? child : document.createTextNode(child);
this.appendChild(node);
return this;
}
}
/* shortcut that feels like jQuery */
const $ = sel => new Q(sel);
export default $;
import $ from './mini-wrapper.js';
// create
$('<div>').addClass('card').attr('data-id', 42);
// select
$('.item').addClass('highlight').attr('data-live', '1');
// grab the first matched node when you need raw DOM
const firstItem = $('.item').get(); // native HTMLElement
firstItem.focus(); // native method still works
https://medium.com/codetodeploy/3-vanilla-lite-dom-patterns-that-achieve-jquerys-ease-1f7b92565419
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment