v1.0.0

🎨 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 of html() 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.