Config Engine
Declarative component initialisation with JSON configuration. Setup once, update anytime, clean up when done.
Why Config Engine?
Declarative
Define components with JSON, not imperative code
Mutable
Update configuration at runtime with deep merging
Inspectable
Retrieve current config for debugging
Cleanable
Reset components and free resources
<div class="row">
<div class="col-6 mb-4">
<div class="card h-full">
<div class="card-body text-center">
<div class="text-primary mb-3" data-icon="code"></div>
<h4 class="font-semibold mb-2">Declarative</h4>
<p class="text-sm text-muted mb-0">Define components with JSON, not imperative code</p>
</div>
</div>
</div>
<div class="col-6 mb-4">
<div class="card h-full">
<div class="card-body text-center">
<div class="text-primary mb-3" data-icon="refresh"></div>
<h4 class="font-semibold mb-2">Mutable</h4>
<p class="text-sm text-muted mb-0">Update configuration at runtime with deep merging</p>
</div>
</div>
</div>
<div class="col-6 mb-4">
<div class="card h-full">
<div class="card-body text-center">
<div class="text-primary mb-3" data-icon="search"></div>
<h4 class="font-semibold mb-2">Inspectable</h4>
<p class="text-sm text-muted mb-0">Retrieve current config for debugging</p>
</div>
</div>
</div>
<div class="col-6 mb-4">
<div class="card h-full">
<div class="card-body text-center">
<div class="text-primary mb-3" data-icon="close"></div>
<h4 class="font-semibold mb-2">Cleanable</h4>
<p class="text-sm text-muted mb-0">Reset components and free resources</p>
</div>
</div>
</div>
</div>Basic Setup
Initialise multiple components at once with a single configuration object.
// Initialise components declaratively
$.setup({
// Selector: configuration
'#my-modal': {
component: 'modal',
options: { backdrop: true, keyboard: true }
},
'.product-card': {
component: 'card',
options: { hover: true }
},
'#main-tabs': {
component: 'tabs',
options: { animation: true, activeIndex: 0 }
}
});
Supported Components (16 total)
card
Content containers with hover and click behaviour.
modal
Overlays for focused tasks and dialogs.
tabs
Switch between panels without leaving the page.
accordion
Expand and collapse groups of content.
tooltip
Small hints beside controls or links.
carousel
Browse a sequence of slides or images.
dropdown
Open menus and choose from a list.
badge
Highlight a status, label or count.
backToTop
Return to the top of a long page.
buttonGroup
Keep related actions or toggles together.
loader
Show progress while content is loading.
breadcrumbs
Show the path to the current page.
navbar
Build the main site navigation.
notification
Show desktop notifications with permission.
timer
Count down and act when time runs out.
alarm
Schedule a notification for a set time.
→ View complete component reference with live demos
Event Binding
Bind event handlers directly in configuration using inline functions or action objects.
$.setup({
// Inline function handler
'#submit-btn': {
events: {
click: (e, $el) => {
e.preventDefault();
$el.text('Submitted!');
}
}
},
// Multiple events
'#search-input': {
events: {
focus: (e, $el) => $el.addClass('focused'),
blur: (e, $el) => $el.removeClass('focused'),
input: (e, $el) => console.log($el.val())
}
},
// Action objects for declarative changes
'#theme-toggle': {
events: {
click: [
{ toggleClass: 'active' },
{ target: 'body', toggleClass: 'dm-theme-dark' }
]
}
}
});
<div class="flex gap-4 items-center">
<button type="button" id="demo-click-btn" class="btn btn-primary">Click me</button>
<span id="demo-click-result" class="text-muted">Click count: 0</span>
</div>/**
* Try it - from public/showcase/config.
*/
export function mount(root) {
let clickCount = 0;
$.setup({
'#demo-click-btn': {
events: {
click: (e, $el) => {
clickCount++;
$(root).find('#demo-click-result').text('Click count: ' + clickCount);
}
}
}
});
}DOMReady Initialisation
The config engine automatically handles DOMContentLoaded, with support for global and per-selector initialisation callbacks.
Automatic DOMContentLoaded Detection
// Config automatically waits for DOM if needed
$.setup({
'#my-element': {
component: 'card',
options: { collapsible: true }
}
});
// ✅ If DOM is loading: queued for DOMContentLoaded
// ✅ If DOM is ready: executes immediately
Global $init Callback
Use $init for code that should run once when all configs are processed:
$.setup({
$init() {
// Runs once after all selectors are configured
console.log('Config engine initialised!');
Domma.icons.scan(); // Scan for icons
Domma.theme.init(); // Initialise theme
},
'#modal': {
component: 'modal',
options: { backdrop: true }
},
'#tabs': {
component: 'tabs',
options: { activeIndex: 0 }
}
});
Per-Selector init Callbacks
Each selector can have its own initialisation callback that receives the DommaCollection:
$.setup({
'#user-card': {
init($el) {
// Runs when this selector is configured
// Receives DommaCollection as first argument
console.log('User card initialised:', $el);
// Fetch and populate data
const userId = $el.data('user-id');
loadUserData(userId).then(data => {
$el.find('.name').text(data.name);
$el.find('.avatar').attr('src', data.avatar);
});
},
component: 'card',
options: { hoverable: true }
},
'#status-indicator': {
init($el) {
// Check server status on init
checkServerStatus().then(online => {
$el.addClass(online ? 'online' : 'offline');
});
},
initial: {
text: 'Checking...'
}
}
});
Standalone ready() Helper
For manual DOMReady callbacks outside of config:
// Standard method
Domma.ready(() => {
console.log('DOM is ready!');
// Your initialisation code
});
// Alias
$.ready(() => {
console.log('This also works!');
});
// Executes immediately if DOM is already ready
// Otherwise waits for DOMContentLoaded
Check the console for initialisation logs.
<div class="flex gap-4 items-center mb-3">
<div id="demo-init-status" class="p-4 rounded demo-update-box-style">
Waiting for initialisation...
</div>
</div>
<p class="text-sm text-muted">Check the console for initialisation logs.</p>/**
* Try it - from public/showcase/config.
*/
export function mount(root) {
// Demo: DOMReady initialisation
$.setup({
$init() {
console.log('✅ $init callback executed - all configs processed');
$(root).find('#demo-init-status')
.html('<strong style="color: #10b981;">✓ Initialised!</strong><br>$init callback executed successfully')
.css({ 'background': '#d1fae5', 'color': '#065f46' });
},
'#demo-init-status': {
init($el) {
console.log('✅ Per-selector init callback for #demo-init-status', $el);
setTimeout(() => {
$el.append('<br><small>Per-selector init also ran!</small>');
}, 500);
}
}
});
}Zero Boilerplate: No need for manual
DOMContentLoadedlisteners. The config engine handles everything automatically!
Initial State
Set initial properties like CSS, text, HTML, classes, and attributes.
$.setup({
'#welcome-message': {
initial: {
text: 'Welcome to Domma!',
css: { color: 'var(--dm-primary)', fontWeight: 'bold' },
addClass: 'animated fadeIn'
}
},
'#status-badge': {
initial: {
html: 'Online',
attr: { 'data-status': 'online', 'aria-label': 'Status' }
}
},
'.disabled-section': {
initial: {
addClass: 'opacity-50',
attr: { 'aria-disabled': 'true' }
}
}
});
Available Properties
| Property | Description | Example |
|---|---|---|
text |
Set text content | text: 'Hello' |
html |
Set HTML content | html: 'Bold' |
css |
Apply CSS styles | css: { color: 'red' } |
addClass |
Add CSS classes | addClass: 'active highlighted' |
removeClass |
Remove CSS classes | removeClass: 'hidden' |
toggleClass |
Toggle CSS classes | toggleClass: 'expanded' |
attr |
Set attributes | attr: { disabled: true } |
Runtime Updates
Modify configuration after initialisation with $.update(). Changes are deep-merged.
// Initial setup
$.setup({
'#my-modal': {
component: 'modal',
options: { backdrop: true, keyboard: true }
}
});
// Later: update options
$.update('#my-modal', {
options: { backdrop: false } // backdrop changed, keyboard preserved
});
// Add new event handlers
$.update('#my-modal', {
events: {
click: () => console.log('Modal clicked')
}
});
// Update initial state
$.update('#status', {
initial: {
text: 'Updated status',
addClass: 'pulse'
}
});
<div class="flex gap-4 items-center mb-3">
<div id="demo-update-box" class="p-4 rounded demo-update-box-style">
Original State
</div>
</div>
<div class="flex gap-2">
<button type="button" id="demo-update-1" class="btn btn-outline btn-sm">Update Text</button>
<button type="button" id="demo-update-2" class="btn btn-outline btn-sm">Update Style</button>
<button type="button" id="demo-update-3" class="btn btn-outline btn-sm">Reset</button>
</div>/**
* Try it - from public/showcase/config.
*/
export function mount(root) {
// Demo: Runtime updates
$.setup({
'#demo-update-box': {
initial: {
text: 'Original State',
css: {background: 'var(--dm-gray-200)'}
}
},
'#demo-update-1': {
events: {
click: () => $.update('#demo-update-box', {
initial: {text: 'Text Updated!'}
})
}
},
'#demo-update-2': {
events: {
click: () => $.update('#demo-update-box', {
initial: {
css: {background: 'var(--dm-primary)', color: 'var(--dm-white)'}
}
})
}
},
'#demo-update-3': {
events: {
click: () => $.update('#demo-update-box', {
initial: {
text: 'Original State',
css: {background: 'var(--dm-gray-200)', color: 'inherit'}
}
})
}
}
});
}Configuration Inspection
Retrieve current configuration for debugging or dynamic adjustments.
// Get config for specific selector
const modalConfig = $.config('#my-modal');
console.log(modalConfig);
// { component: 'modal', options: { backdrop: true, keyboard: true } }
// Get all configurations
const allConfigs = $.config();
console.log(allConfigs);
// { '#my-modal': {...}, '.card': {...}, ... }
<button type="button" id="demo-inspect" class="btn btn-primary btn-sm mb-3">Inspect $.config()</button>
<div id="demo-inspect-result" class="demo-result-config hidden"></div>/**
* Current Page Configurations - from public/showcase/config.
*/
export function mount(root) {
// Demo: Config inspection
$.setup({
'#demo-inspect': {
events: {
click: () => {
const config = $.config();
const result = $(root).find('#demo-inspect-result');
result.removeClass('hidden');
result.text(JSON.stringify(config, (key, value) => {
if (typeof value === 'function') return '[Function]';
return value;
}, 2));
}
}
}
});
}Cleanup
Reset configuration, destroy components, and unbind events with $.reset().
// Reset specific selector
$.reset('#my-modal');
// - Destroys the modal component
// - Unbinds all event handlers
// - Clears stored configuration
// Reset ALL configurations
$.reset();
// Resets every selector that was configured
Memory Management: Always call
$.reset()when removing configured elements from the DOM to prevent memory leaks.
Real-World Example
A complete form with validation, dynamic UI, and component integration.
$.setup({
// Form validation and submission
'#contact-form': {
events: {
submit: (e, $form) => {
e.preventDefault();
const data = {
name: $('#name').val(),
email: $('#email').val()
};
// Show loading state
$('#submit-btn').text('Sending...').attr('disabled', true);
// Simulate API call
setTimeout(() => {
// Show success toast (better UX for transient feedback)
Domma.elements.toast('Message sent successfully!', {
type: 'success',
duration: 3000
});
// Reset form and button
$form[0].reset();
$('#email').removeClass('success error');
$('#submit-btn').text('Send Message').attr('disabled', false);
}, 1500);
}
}
},
// Input validation on blur
'#email': {
events: {
blur: (e, $el) => {
const valid = $el.val().includes('@');
$el.removeClass('success error')
.addClass(valid ? 'success' : 'error');
}
}
}
});
<form id="live-form" class="grid grid-cols-2 gap-4 max-w-500px">
<div class="form-group">
<label class="form-label">Name</label>
<input type="text" id="live-name" class="form-input" placeholder="Your name">
</div>
<div class="form-group">
<label class="form-label">Email</label>
<input type="email" id="live-email" class="form-input" placeholder="you@example.com">
</div>
<div class="col-span-2">
<button type="submit" id="live-submit" class="btn btn-primary">Send Message</button>
</div>
</form>/**
* Live Demo - from public/showcase/config.
*/
export function mount(root) {
// Demo: Live form
$.setup({
'#live-email': {
events: {
blur: (e, $el) => {
const val = $el.val();
if (val) {
const valid = val.includes('@');
$el.removeClass('success error warning')
.addClass(valid ? 'success' : 'error');
}
},
input: (e, $el) => {
$el.removeClass('success error warning');
}
}
},
'#live-form': {
events: {
submit: (e, $form) => {
e.preventDefault();
const $btn = $(root).find('#live-submit');
// Show loading state
$btn.text('Sending...').attr('disabled', true);
// Simulate API call
setTimeout(() => {
// Show success toast
E.toast('Message sent successfully!', {
type: 'success',
duration: 3000
});
// Reset form and button
$form[0].reset();
$form.find('input').removeClass('success error');
$btn.text('Send Message').attr('disabled', false);
}, 1000);
}
}
}
});
}API Reference
| Method | Description |
|---|---|
$.setup(config) |
Process initial configuration object. Keys are CSS selectors, values are config objects with component, options, initial, and events properties. |
$.update(selector, changes) |
Deep-merge changes into existing configuration. Updates component options, re-applies initial properties, and rebinds events. |
$.config(selector?) |
Retrieve configuration. With selector: returns config for that selector. Without: returns all configurations as object. |
$.reset(selector?) |
Reset configuration. Destroys components, unbinds events, clears config. Without selector: resets all. |
$.ready(callback) |
Register a callback to run when DOM is ready. Executes immediately if DOM is already ready, otherwise waits for DOMContentLoaded. Also available as Domma.ready(). |
Configuration Properties
| Property | Description |
|---|---|
$init |
Global initialisation callback. Runs once when all configs are processed, after DOM is ready. |
init |
Per-selector initialisation callback. Receives DommaCollection as first argument. Runs when this selector's config is processed. |
component |
Component type to initialise (e.g., 'modal', 'card', 'tabs'). See supported components list above. |
options |
Component-specific options object passed to the component factory. |
initial |
Initial state properties (css, text, html, addClass, removeClass, toggleClass, attr). |
events |
Event handlers object. Keys are event names, values are handler functions or action objects. |