π¨ DOM Manipulation
OnigiriJS provides a jQuery-like API for DOM manipulation with method chaining, making it easy to work with elements.
Selection
Basic Selection
// Select by CSS selector
const buttons = O('.button');
const container = O('#container');
const items = O('div.item');
const links = O('a[href^="http"]');
// Select with context
const containerItems = O('.item', document.querySelector('#container'));
// Select by element
const element = document.querySelector('.widget');
const wrapped = O(element);
// Select from NodeList
const nodeList = document.querySelectorAll('.item');
const wrapped = O(nodeList);
Method Chaining
// Chain multiple operations
O('.item')
.addClass('active')
.attr('data-id', '123')
.css({ color: 'red', fontSize: '16px' })
.text('Updated')
.fadeIn(300);
// Complex chain
O('#onigiri-card')
.removeClass('hidden')
.addClass('visible animated')
.attr('data-status', 'ready')
.css({
transform: 'scale(1)',
opacity: '1'
})
.html('<h2>π Ready!</h2>');
Classes
Adding Classes
// Add single class
O('.element').addClass('active');
// Add multiple classes (space-separated)
O('.element').addClass('active visible highlighted');
Removing Classes
// Remove single class
O('.element').removeClass('active');
// Remove multiple classes
O('.element').removeClass('active visible');
Toggling Classes
// Toggle class
O('.element').toggleClass('active');
// Toggle on click
O('.toggle-button').on('click', function() {
O('.menu').toggleClass('open');
});
Checking Classes
// Check if element has class
if (O('.element').hasClass('active')) {
console.log('Element is active');
}
// Conditional logic
const menu = O('.menu');
if (menu.hasClass('open')) {
menu.removeClass('open').slideUp(300);
} else {
menu.addClass('open').slideDown(300);
}
Attributes & Data
Get/Set Attributes
// Get attribute
const id = O('.element').attr('data-id');
const href = O('a').attr('href');
// Set attribute
O('.element').attr('data-id', '123');
O('img').attr('src', '/images/onigiri.jpg');
// Set multiple attributes
O('img')
.attr('src', '/images/onigiri.jpg')
.attr('alt', 'Delicious Onigiri')
.attr('loading', 'lazy');
Remove Attributes
// Remove attribute
O('.element').removeAttr('disabled');
O('input').removeAttr('readonly');
Data Attributes
// Get data attribute
const userId = O('.user-card').data('userId');
const status = O('.widget').data('status');
// Set data attribute
O('.user-card').data('userId', '456');
O('.widget').data('status', 'active');
// Data attributes are stored in dataset
// data-user-id becomes data('userId')
Content
HTML Content
// Get HTML
const html = O('#container').html();
// Set HTML
O('#container').html('<p>New content</p>');
// Complex HTML
O('#widget').html(\`
<div class="onigiri-card">
<h2>π Salmon Onigiri</h2>
<p>Price: $3.50</p>
<button>Order Now</button>
</div>
\`);
Text Content
// Get text (strips HTML tags)
const text = O('.element').text();
// Set text (auto-escapes HTML)
O('.element').text('<script>alert("safe")</script>');
// Displays: <script>alert("safe")</script>
// Safe user input display
const userInput = getUserInput();
O('#display').text(userInput); // Always safe
Value (Form Inputs)
// Get input value
const email = O('#email').val();
const password = O('#password').val();
// Set input value
O('#email').val('user@example.com');
O('#search').val('');
// Form data collection
const formData = {
email: O('[name="email"]').val(),
password: O('[name="password"]').val(),
remember: O('[name="remember"]').val()
};
Styles
Get/Set CSS
// Get computed style
const color = O('.element').css('color');
const fontSize = O('.element').css('font-size');
// Set single property
O('.element').css('color', 'red');
O('.element').css('font-size', '16px');
// Set multiple properties
O('.element').css({
color: 'red',
fontSize: '16px',
fontWeight: 'bold',
padding: '10px',
margin: '5px 0'
});
// Dynamic styles
O('.card').css({
transform: \`translateX(\${offset}px)\`,
opacity: visible ? '1' : '0'
});
Show/Hide
// Show element
O('.element').show();
// Hide element
O('.element').hide();
// Toggle visibility
const toggle = () => {
const el = O('.menu');
if (el.css('display') === 'none') {
el.show();
} else {
el.hide();
}
};
DOM Manipulation
Append Content
// Append HTML string
O('#list').append('<li>New Item</li>');
// Append multiple items
O('#list').append(\`
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
\`);
// Append element
const newDiv = document.createElement('div');
newDiv.textContent = 'New content';
O('#container').append(newDiv);
// Dynamic append
items.forEach(item => {
O('#list').append(\`
<li data-id="\${item.id}">
π \${item.name}
</li>
\`);
});
Prepend Content
// Prepend (add to beginning)
O('#list').prepend('<li>First Item</li>');
// Add notification at top
O('#notifications').prepend(\`
<div class="alert">New message! π</div>
\`);
Remove Elements
// Remove element
O('.element').remove();
// Remove all items
O('.item').remove();
// Remove on click
O('.delete-btn').on('click', function() {
O(this).parent().remove();
});
Empty Elements
// Remove all children
O('#container').empty();
// Clear list
O('#todo-list').empty();
// Clear and rebuild
O('#list').empty();
items.forEach(item => {
O('#list').append(\`<li>\${item}</li>\`);
});
Traversal
Find Children
// Find descendant elements
const items = O('#container').find('.item');
const buttons = O('.card').find('button');
// Find and manipulate
O('.container')
.find('.button')
.addClass('primary');
Parent
// Get parent element
const parent = O('.child').parent();
// Manipulate parent
O('.delete-btn').on('click', function() {
O(this).parent().addClass('deleting');
});
Children
// Get direct children
const children = O('#container').children();
// Style all children
O('#list')
.children()
.addClass('list-item')
.css({ padding: '10px' });
Siblings
// Get all siblings
const siblings = O('.active').siblings();
// Highlight siblings
O('.selected')
.siblings()
.addClass('dimmed');
Iteration
Each Method
// Iterate over elements
O('.item').each(function(el, index) {
console.log('Element', index, el);
// 'this' is the current element
this.style.animationDelay = \`\${index * 100}ms\`;
});
// Complex iteration
O('.onigiri-card').each(function(el, idx) {
const id = el.dataset.id;
const name = el.querySelector('h3').textContent;
console.log(\`Card \${idx}: \${name} (ID: \${id})\`);
// Add click handler
O(el).on('click', () => {
console.log(\`Clicked \${name}\`);
});
});
Practical Examples
Dynamic List Builder
function buildOnigiriMenu(items) {
const container = O('#menu');
container.empty();
items.forEach((item, index) => {
container.append(\`
<div class="menu-item" data-id="\${item.id}">
<h3>π \${item.name}</h3>
<p>\${item.description}</p>
<span class="price">$\${item.price.toFixed(2)}</span>
<button class="order-btn">Order</button>
</div>
\`);
});
// Add event handlers
O('.order-btn').on('click', function() {
const item = O(this).parent();
const id = item.data('id');
orderOnigiri(id);
});
}
Form Validation UI
function showValidationErrors(errors) {
// Clear previous errors
O('.error-message').remove();
O('.input-error').removeClass('input-error');
// Show new errors
Object.keys(errors).forEach(field => {
const input = O(\`[name="\${field}"]\`);
input.addClass('input-error');
input.parent().append(\`
<span class="error-message">
\${errors[field].join(', ')}
</span>
\`);
});
}
Tab System
O('.tab-button').on('click', function() {
const tabId = O(this).data('tab');
// Update buttons
O('.tab-button')
.removeClass('active')
.attr('aria-selected', 'false');
O(this)
.addClass('active')
.attr('aria-selected', 'true');
// Update panels
O('.tab-panel')
.removeClass('active')
.hide();
O(\`#\${tabId}\`)
.addClass('active')
.fadeIn(300);
});
Accordion
O('.accordion-header').on('click', function() {
const content = O(this).siblings('.accordion-content');
const isOpen = O(this).hasClass('open');
// Close all
O('.accordion-header')
.removeClass('open')
.siblings('.accordion-content')
.slideUp(300);
// Open clicked (if it was closed)
if (!isOpen) {
O(this).addClass('open');
content.slideDown(300);
}
});
Search Filter
O('#search').on('input', function() {
const query = this.value.toLowerCase();
O('.item').each(function(el) {
const text = el.textContent.toLowerCase();
const matches = text.includes(query);
if (matches) {
O(el).show().removeClass('filtered');
} else {
O(el).hide().addClass('filtered');
}
});
// Update count
const visible = O('.item:not(.filtered)').length;
O('#result-count').text(\`\${visible} results\`);
});
Shopping Cart UI
function updateCart(cart) {
const container = O('#cart-items');
container.empty();
if (cart.items.length === 0) {
container.html('<p>Your cart is empty π</p>');
return;
}
cart.items.forEach(item => {
container.append(\`
<div class="cart-item" data-id="\${item.id}">
<span class="name">\${item.name}</span>
<span class="quantity">Γ\${item.quantity}</span>
<span class="price">$\${item.total}</span>
<button class="remove">Γ</button>
</div>
\`);
});
// Update total
O('#cart-total').text(\`$\${cart.total.toFixed(2)}\`);
// Remove buttons
O('.cart-item .remove').on('click', function() {
const id = O(this).parent().data('id');
removeFromCart(id);
});
}
π Pro Tip: All DOM methods return the OnigiriJS object, allowing you to chain multiple operations together for cleaner code!
DOM Manipulation Best Practices
- Use method chaining for multiple operations
- Cache selectors in variables when used multiple times
- Use event delegation for dynamic elements
- Use
text()instead ofhtml()for user input - Empty containers before rebuilding to avoid memory leaks
- Use
data()attributes for storing element metadata - Batch DOM updates to minimize reflows
β Development Roadmap
Track the progress of OnigiriJS modules. Tasks are marked complete by the development team.
OnigiriJS Module Roadmap
Implementation progress of planned modules
6 / 21 completed (29%)
onigiri-state
Shared global & scoped state management
onigiri-directives
Declarative DOM bindings (o-show, o-model, etc.)
onigiri-resource
REST-style data models over AJAX
onigiri-observe
Intersection & Mutation observer helpers
onigiri-humhub-ui
Standard HumHub UI abstractions (modal, notify, confirm)
onigiri-lifecycle
Component lifecycle hooks
onigiri-guard
Debounce, throttle, single-run guards
onigiri-scroll
Scroll save/restore & helpers (PJAX-friendly)
onigiri-permission
Client-side permission awareness
onigiri-portal
DOM teleport / overlay mounting
onigiri-router
Micro router (non-SPA, PJAX-first)
onigiri-sanitize
HTML & input sanitization
onigiri-shortcut
Keyboard shortcut manager
onigiri-queue
Sequential async task runner
onigiri-gesture
Touch & swipe helpers
onigiri-devtools
Debugging & inspection helpers
onigiri-plugin
Plugin registration system
onigiri-time
Relative time & timezone utilities
onigiri-emojis
Emoji Picker and Manager
onigiri-tasks
Task Management
onigiri-polls
Polls creation and management
Note: Task completion is managed by the OnigiriJS development team.