Numbered Instances — Method 4
Quick Start (30 seconds)
// Create three boxes — same tag, different identifiers
const boxes = createElement.bulk({
DIV_1: { textContent: 'Box One', classList: { add: ['box'] } },
DIV_2: { textContent: 'Box Two', classList: { add: ['box'] } },
DIV_3: { textContent: 'Box Three', classList: { add: ['box'] } }
});
// Style each one differently
boxes.DIV_1.update({ style: { background: '#ff6b6b' } });
boxes.DIV_2.update({ style: { background: '#4ecdc4' } });
boxes.DIV_3.update({ style: { background: '#45b7d1' } });
// Append all
boxes.appendTo(Elements.container);What is Method 4?
Method 4 is the technique of creating multiple elements of the same tag type within a single createElement.bulk() call, by using numbered suffixes in your keys.
Without numbered suffixes, you cannot have two elements with the same key name in a JavaScript object:
// This does NOT work — JavaScript objects cannot have duplicate keys
createElement.bulk({
DIV: { textContent: 'First' },
DIV: { textContent: 'Second' } // Overwrites the first!
});Numbered instances solve this:
// This DOES work — each key is unique
createElement.bulk({
DIV_1: { textContent: 'First' },
DIV_2: { textContent: 'Second' }
});
// Both create <div> elements, both are accessible separatelySyntax
// Number suffix
const result = createElement.bulk({
TAGNAME_1: { /* config */ },
TAGNAME_2: { /* config */ },
TAGNAME_3: { /* config */ }
});
// Named suffix (any string after underscore)
const result = createElement.bulk({
BUTTON_save: { /* config */ },
BUTTON_cancel: { /* config */ },
BUTTON_delete: { /* config */ }
});
// Access each element by its full key
result.TAGNAME_1
result.BUTTON_saveThe suffix can be any string — a number, a word, or a combination. The only requirement is that each key in the object is unique.
How Tag Names are Parsed
This is the same rule as always, but it is especially important to understand with numbered instances:
Key → Tag Created → Suffix (identifier only)
──────────────────────────────────────────────────────────
DIV_1 → <div> → 1
DIV_2 → <div> → 2
P_intro → <p> → intro
P_body → <p> → body
SPAN_label → <span> → label
SPAN_value → <span> → value
BUTTON_save → <button> → save
BUTTON_cancel → <button> → cancel
LI_1 → <li> → 1
LI_2 → <li> → 2
LI_3 → <li> → 3Everything before the first _ is the tag name. Everything after is just an identifier that becomes part of the key name on the result object.
Why Does This Exist?
Creating Multiple Elements of the Same Type
The most common scenario is creating several divs, paragraphs, list items, or buttons that have the same HTML tag but different content or styling.
In plain JavaScript:
// Creating 4 tab buttons — repetitive
const tab1 = document.createElement('button');
tab1.textContent = 'Overview';
tab1.className = 'tab';
tab1.dataset.panel = 'overview';
const tab2 = document.createElement('button');
tab2.textContent = 'Details';
tab2.className = 'tab';
tab2.dataset.panel = 'details';
const tab3 = document.createElement('button');
tab3.textContent = 'Reviews';
tab3.className = 'tab';
tab3.dataset.panel = 'reviews';
const tab4 = document.createElement('button');
tab4.textContent = 'FAQ';
tab4.className = 'tab';
tab4.dataset.panel = 'faq';With numbered instances:
const tabs = createElement.bulk({
BUTTON_1: { textContent: 'Overview', classList: { add: ['tab'] }, dataset: { panel: 'overview' } },
BUTTON_2: { textContent: 'Details', classList: { add: ['tab'] }, dataset: { panel: 'details' } },
BUTTON_3: { textContent: 'Reviews', classList: { add: ['tab'] }, dataset: { panel: 'reviews' } },
BUTTON_4: { textContent: 'FAQ', classList: { add: ['tab'] }, dataset: { panel: 'faq' } }
});Same information. The second version groups all related elements together, makes the structure scannable, and keeps everything accessible by name.
Why Named Suffixes are Often Better Than Numbers
Numbers are fine, but descriptive names are often more readable:
// Numbers — works, but requires remembering which number is which
const result = createElement.bulk({
BUTTON_1: { textContent: 'Save' },
BUTTON_2: { textContent: 'Cancel' },
BUTTON_3: { textContent: 'Delete' }
});
result.BUTTON_1 // What was this? I have to scroll up to check.
// Descriptive names — immediately clear
const result = createElement.bulk({
BUTTON_save: { textContent: 'Save' },
BUTTON_cancel: { textContent: 'Cancel' },
BUTTON_delete: { textContent: 'Delete' }
});
result.BUTTON_save // Crystal clear.Use numbers when the elements are truly interchangeable (like list items), and use descriptive names when each element has a specific role.
Mental Model: A Numbered Factory
Think of numbered instances like a stamp press that produces multiple parts of the same shape.
You define the stamp (the tag name), and each press of the stamp produces a uniquely numbered part (the suffix). All parts are the same type, but each one is individually tracked and accessible.
Stamp: DIV
Press 1 → DIV_1 → <div>First content</div>
Press 2 → DIV_2 → <div>Second content</div>
Press 3 → DIV_3 → <div>Third content</div>
All stored in one result object — each accessible by number.Basic Usage
Creating Multiple Cards
const cards = createElement.bulk({
DIV_1: {
className: 'card',
innerHTML: '<h3>Feature One</h3><p>Fast and reliable</p>',
style: { padding: '20px', background: 'white', borderRadius: '8px' }
},
DIV_2: {
className: 'card',
innerHTML: '<h3>Feature Two</h3><p>Simple to use</p>',
style: { padding: '20px', background: 'white', borderRadius: '8px' }
},
DIV_3: {
className: 'card',
innerHTML: '<h3>Feature Three</h3><p>Fully featured</p>',
style: { padding: '20px', background: 'white', borderRadius: '8px' }
}
});
// Access individually
cards.DIV_1.style.borderTop = '3px solid #007bff';
cards.DIV_2.style.borderTop = '3px solid #28a745';
cards.DIV_3.style.borderTop = '3px solid #ffc107';
// Append all
cards.appendTo(Elements.featuresSection);Navigation Tabs
const tabs = createElement.bulk({
BUTTON_overview: {
textContent: 'Overview',
classList: { add: ['tab', 'tab--active'] },
dataset: { panel: 'overview' },
addEventListener: ['click', switchTab]
},
BUTTON_specs: {
textContent: 'Specifications',
classList: { add: ['tab'] },
dataset: { panel: 'specs' },
addEventListener: ['click', switchTab]
},
BUTTON_reviews: {
textContent: 'Reviews',
classList: { add: ['tab'] },
dataset: { panel: 'reviews' },
addEventListener: ['click', switchTab]
},
BUTTON_faq: {
textContent: 'FAQ',
classList: { add: ['tab'] },
dataset: { panel: 'faq' },
addEventListener: ['click', switchTab]
}
});
function switchTab(e) {
// Remove active from all tabs
tabs.forEach((element) => {
element.classList.remove('tab--active');
});
// Set active on clicked tab
e.target.classList.add('tab--active');
// Show the relevant panel
showPanel(e.target.dataset.panel);
}
tabs.appendTo(Elements.tabBar);Color Swatches
const swatches = createElement.bulk({
SWATCH_red: {
classList: { add: ['swatch'] },
dataset: { color: '#ff6b6b' },
style: { background: '#ff6b6b', width: '40px', height: '40px', borderRadius: '50%', cursor: 'pointer' },
addEventListener: ['click', selectColor]
},
SWATCH_teal: {
classList: { add: ['swatch'] },
dataset: { color: '#4ecdc4' },
style: { background: '#4ecdc4', width: '40px', height: '40px', borderRadius: '50%', cursor: 'pointer' },
addEventListener: ['click', selectColor]
},
SWATCH_blue: {
classList: { add: ['swatch'] },
dataset: { color: '#45b7d1' },
style: { background: '#45b7d1', width: '40px', height: '40px', borderRadius: '50%', cursor: 'pointer' },
addEventListener: ['click', selectColor]
},
SWATCH_green: {
classList: { add: ['swatch'] },
dataset: { color: '#96ceb4' },
style: { background: '#96ceb4', width: '40px', height: '40px', borderRadius: '50%', cursor: 'pointer' },
addEventListener: ['click', selectColor]
}
});
function selectColor(e) {
Elements.colorPreview.update({
style: { background: e.target.dataset.color }
});
}
swatches.appendTo(Elements.colorPicker);Dynamic List Items
When the number of items is known in advance, numbered instances are clean and readable:
const menuItems = ['Dashboard', 'Analytics', 'Reports', 'Settings', 'Help'];
const menu = createElement.bulk(
menuItems.reduce((config, label, index) => {
config[`LI_${index + 1}`] = {
textContent: label,
classList: { add: ['menu-item'] },
addEventListener: ['click', () => navigateTo(label.toLowerCase())]
};
return config;
}, {})
);
// Append all list items to the UL
menu.forEach((element) => {
Elements.mainMenu.appendChild(element);
});Iterating Over Numbered Instances
The result object's forEach() method iterates over all created elements. This works perfectly with numbered instances:
const indicators = createElement.bulk({
SPAN_1: { className: 'dot' },
SPAN_2: { className: 'dot' },
SPAN_3: { className: 'dot' },
SPAN_4: { className: 'dot' },
SPAN_5: { className: 'dot' }
});
// Iterate over all elements
indicators.forEach((element, key, index) => {
element.dataset.slide = String(index);
element.addEventListener('click', () => goToSlide(index));
});
indicators.appendTo(Elements.carousel);Filtering Numbered Instances
The filter() method works with the same callback pattern as Array.prototype.filter:
const items = createElement.bulk({
DIV_1: { textContent: 'Item 1', dataset: { active: 'true' } },
DIV_2: { textContent: 'Item 2', dataset: { active: 'false' } },
DIV_3: { textContent: 'Item 3', dataset: { active: 'true' } },
DIV_4: { textContent: 'Item 4', dataset: { active: 'false' } }
});
// Get only active items
const activeItems = items.filter(
(element) => element.dataset.active === 'true'
);
console.log(activeItems.length); // 2Updating Multiple Numbered Instances
Use updateMultiple() to update several elements at once:
const steps = createElement.bulk({
STEP_1: { textContent: 'Step 1', className: 'step' },
STEP_2: { textContent: 'Step 2', className: 'step' },
STEP_3: { textContent: 'Step 3', className: 'step' }
});
steps.appendTo(Elements.wizard);
// Mark steps 1 and 2 as complete
steps.updateMultiple({
STEP_1: { classList: { add: ['step--complete'] } },
STEP_2: { classList: { add: ['step--complete'] } },
STEP_3: { classList: { add: ['step--active'] } }
});Common Pitfall: Plain Numbers in Keys Without Underscore
// ❌ Wrong — key starts with a digit, which is invalid as a JavaScript identifier
const result = createElement.bulk({
1_DIV: { textContent: 'Bad' } // Syntax error!
});
// ✅ Correct — underscore separates the tag from the number suffix
const result = createElement.bulk({
DIV_1: { textContent: 'Good' } // Works perfectly
});Always put the tag name first, then the underscore, then the identifier.
Common Pitfall: Duplicate Suffixes
// ❌ Wrong — duplicate keys! The second overwrites the first
const result = createElement.bulk({
DIV_1: { textContent: 'First' },
DIV_1: { textContent: 'Second' } // Overwrites DIV_1!
});
// ✅ Correct — unique keys
const result = createElement.bulk({
DIV_1: { textContent: 'First' },
DIV_2: { textContent: 'Second' }
});JavaScript object keys must be unique. If you use the same key twice, only the last definition is kept.
Naming Convention Summary
For numbered groups (interchangeable items):
LI_1, LI_2, LI_3 ← clear, ordinal
SLIDE_1, SLIDE_2 ← clear, ordinal
For named roles (distinct purposes):
BUTTON_save, BUTTON_cancel ← purpose-driven
SPAN_label, SPAN_value ← role-driven
DIV_header, DIV_footer ← position-driven
For mixed (type + role):
INPUT_email, INPUT_phone ← type + role
BUTTON_primary, BUTTON_ghost ← type + style variantSummary
Method 4 — Numbered Instances — is the solution to creating multiple elements of the same HTML tag type in a single createElement.bulk() call.
Key points:
- ✅ Append
_suffixto any tag name to create unique keys for same-type elements - ✅ The suffix can be a number (
DIV_1) or any descriptive string (BUTTON_save) - ✅ The tag is always the part before the first
_ - ✅ All numbered instances are accessible by their full key name on the result object
- ✅
forEach(),filter(), andupdateMultiple()all work naturally with numbered instances
What's Next?
- 08 — Factory Functions — Reusable element creation with function-based factories
- 09 — Component Pattern — Full component encapsulation with the bulk system