invokers
v2.2.0
Published
A powerful, platform-first JavaScript library for creating modern user interfaces with declarative HTML. Features universal command chaining, conditional execution, and declarative workflow orchestration via `data-and-then` attributes and `<and-then>` ele
Downloads
455
Maintainers
Keywords
Readme
✨ Invokers
Write Interactive HTML Without Writing JavaScript
Invokers lets you write future-proof HTML interactions without custom JavaScript. It's a polyfill for the upcoming HTML Invoker Commands API and Interest Invokers (hover cards, tooltips), with extended commands available via modular command packs or the invokers/compatible build for real-world needs like toggling, fetching, media controls, and complex workflow chaining.
Table of Contents
- Quick Demo
- How Does This Compare?
- Why Invokers?
- Modular Architecture
- Installation & Basic Usage
- Command Packs
- Command Cheatsheet
- Command Syntax Guide
- Comprehensive Demo
- Quick Start Examples
- Progressive Learning Guide
- Plugin System
- Extended Commands
- Advanced
commandforSelectors - Migration Guide
- Documentation
- Performance
- Development
- Browser Support
- Contributing
- License
Features
- ✅ Standards-First: Built on the W3C/WHATWG
commandattribute and Interest Invokers proposals. Learn future-proof skills, not framework-specific APIs. - 🧩 Polyfill & Superset: Provides the standard APIs in all modern browsers and extends them with a rich set of custom commands.
- ✍️ Declarative & Readable: Describe what you want to happen in your HTML, not how in JavaScript. Create UIs that are self-documenting.
- 🔗 Universal Command Chaining: Chain any command with any other using
data-and-thenattributes or declarative<and-then>elements for complex workflows. - 🎯 Conditional Execution: Execute different command sequences based on success/error states with built-in conditional logic.
- 🔄 Lifecycle Management: Control command execution with states like
once,disabled, andcompletedfor sophisticated interaction patterns. - ♿ Accessible by Design: Automatically manages
aria-*attributes and focus behavior, guiding you to build inclusive interfaces. - 🌐 Server-Interactive: Fetch content and update the DOM without a page reload using simple, declarative HTML attributes.
- 💡 Interest Invokers: Create hover cards, tooltips, and rich hints that work across mouse, keyboard, and touch with the
interestforattribute. - 🚀 Zero Dependencies & Tiny: A featherlight addition to any project, framework-agnostic, and ready to use in seconds.
- 🎨 View Transitions: Built-in, automatic support for the View Transition API for beautiful, animated UI changes with zero JS configuration.
- 🔧 Singleton Architecture: Optimized internal architecture ensures consistent behavior and prevents duplicate registrations.
- 🚀 New Features:
- Advanced Modules: State management, control flow, components, and forms
- Expression Functions: 40+ built-in functions for reactive computations (
{{concat("Hello", " ", "World")}}) - Loop Commands: Declarative iteration and batch DOM operations
- Random Commands: Generate random data without JavaScript
- Data Commands: Advanced array operations and reactive data binding
- JS Framework Benchmark: Complete declarative implementation of the JS Framework Benchmark
- Performance Optimizations: Batch DOM operations and keyed rendering
Quick Demo
See Invokers in action with this copy-paste example:
<!DOCTYPE html>
<html>
<head>
<!-- Add Invokers via CDN (includes all commands) -->
<script type="module" src="https://esm.sh/invokers/compatible"></script>
</head>
<body>
<!-- Toggle a navigation menu with zero JavaScript -->
<button type="button" command="--toggle" commandfor="nav-menu" aria-expanded="false">
Menu
</button>
<nav id="nav-menu" hidden>
<a href="/home">Home</a>
<a href="/about">About</a>
<!-- Dismiss button that hides itself -->
<button type="button" command="--hide" commandfor="nav-menu">✕</button>
</nav>
<!-- Hover cards work automatically with Interest Invokers -->
<a href="/profile" interestfor="profile-hint">@username</a>
<div id="profile-hint" popover="hint">
<strong>John Doe</strong><br>
Software Developer<br>
📍 San Francisco
</div>
</body>
</html>That's it! No event listeners, no DOM queries, no state management. The HTML describes the behavior, and Invokers makes it work.
Platform Proposals & Standards Alignment
Invokers is built on emerging web platform proposals from the OpenUI Community Group and WHATWG, providing a polyfill today for features that will become native browser APIs tomorrow. This section explains the underlying standards and how Invokers extends them.
HTML Invoker Commands API
The Invoker Commands API is a W3C/WHATWG proposal that introduces the command and commandfor attributes to HTML <button> elements. This allows buttons to declaratively trigger actions on other elements without JavaScript.
Core Proposal Features
commandattribute: Specifies the action to perform (e.g.,show-modal,toggle-popover)commandforattribute: References the target element by IDCommandEvent: Dispatched on the target element when the button is activated- Built-in commands: Native browser behaviors for dialogs and popovers
Example from the Specification
<button command="show-modal" commandfor="my-dialog">Open Dialog</button>
<dialog id="my-dialog">Hello World</dialog>How Invokers Extends This
Invokers provides a complete polyfill for the Invoker Commands API while adding extensive enhancements:
- Extended Command Set: Adds 50+ custom commands (
--toggle,--fetch:get,--media:play, etc.) beyond the spec's basic commands - Advanced Event Triggers: Adds
command-onattribute for any DOM event (click, input, submit, etc.) - Expression Engine: Adds
{{...}}syntax for dynamic command parameters - Command Chaining: Adds
<and-then>elements anddata-and-thenattributes for workflow orchestration - Conditional Logic: Adds success/error state handling with
data-after-success/data-after-error - Lifecycle States: Adds
once,disabled,completedstates for sophisticated interactions
Interest Invokers (Hover Cards & Tooltips)
The Interest Invokers proposal introduces the interestfor attribute for creating accessible hover cards, tooltips, and preview popovers that work across all input modalities.
Core Proposal Features
interestforattribute: Connects interactive elements to hovercard/popover content- Multi-modal Support: Works with mouse hover, keyboard focus, and touchscreen long-press
- Automatic Accessibility: Manages ARIA attributes and focus behavior
- Delay Controls: CSS properties for customizing show/hide timing
- Pseudo-classes:
:interest-sourceand:interest-targetfor styling
Example from the Specification
<a href="/profile" interestfor="user-card">@username</a>
<div id="user-card" popover="hint">User details...</div>How Invokers Extends This
Invokers includes a complete polyfill for Interest Invokers with additional enhancements:
- Extended Element Support: Works on all
HTMLElementtypes (spec currently limits to specific elements) - Touchscreen Long-Press Support: Long-press triggers interest on touch devices
- Advanced Delay Controls: Full support for
interest-delay-start/interest-delay-endCSS properties - Styling Hooks: Adds
interest-source/interest-targetclasses for styling in the polyfill - Combined Usage: Works seamlessly with Invoker Commands on the same elements
Popover API Integration
Invokers has deep integration with the Popover API, automatically handling popover lifecycle and accessibility when using popover attributes.
Automatic Behaviors
- Popover Commands:
toggle-popover,show-popover,hide-popoverwork natively - ARIA Management: Automatic
aria-expandedandaria-detailsattributes - Focus Management: Proper focus restoration when popovers close
- Top Layer Integration: Works with the browser's top layer stacking context
Standards Compliance & Future-Proofing
Current Browser Support
- Chrome/Edge: Full Invoker Commands support (v120+)
- Firefox: Partial support, actively developing
- Safari: Under consideration
- Polyfill Coverage: Invokers provides complete fallback for all browsers
Standards Timeline
- Invoker Commands: Graduated from OpenUI, in WHATWG HTML specification
- Interest Invokers: Active proposal, expected to graduate soon
- Popover API: Already shipping in major browsers
Migration Path
As browsers implement these features natively:
- Invokers will automatically detect native support
- Polyfill behaviors will gracefully disable
- Your HTML markup remains unchanged
- Enhanced features (chaining, expressions) continue to work
Why Invokers vs. Native-Only
While waiting for universal browser support, Invokers provides:
- Immediate Availability: Use these features today in any browser
- Enhanced Functionality: Command chaining, expressions, and advanced workflows
- Backward Compatibility: Works alongside native implementations
- Progressive Enhancement: Adds features without breaking existing code
This standards-first approach ensures your code is future-proof while providing powerful enhancements that complement the core platform proposals.
How Does This Compare?
Invokers is designed to feel like a natural extension of HTML, focusing on client-side interactions and aligning with future web standards. Here’s how its philosophy and approach differ from other popular libraries.
| Feature | Vanilla JS | HTMX | Alpine.js | Stimulus | Invokers | | ----------------------- | ---------- | --------------------------- | --------------------------- | --------------------------- | ----------------------------------------------------- | | Philosophy | Imperative | Hypermedia (Server-centric) | JS in HTML (Component-like) | JS Organization (MVC-like) | Declarative HTML (Browser-centric) | | Standards-Aligned | ✅ | ❌ | ❌ | ❌ | ✅ (Core Mission) | | Primary Use Case | Anything | Server-rendered partials | Self-contained UI components | Organizing complex JS | JS-free UI patterns & progressive enhancement | | JS Required for UI | Always | For server comms | For component logic | Always (in controllers) | Often none for common patterns | | Accessibility | Manual | Manual | Manual | Manual | ✅ (Automatic ARIA management) | | Learning Curve | High | Medium (Hypermedia concepts) | Low (Vue-like syntax) | Medium (Controller concepts) | Very Low (HTML attributes) |
vs HTMX
HTMX makes your server the star; Invokers makes your browser the star.
HTMX is a hypermedia-driven library where interactions typically involve a network request to a server, which returns HTML. Invokers is client-centric, designed to create rich UI interactions directly in the browser, often without any network requests or custom JavaScript.
Use Case: Inline Editing
A user clicks "Edit" to change a name, then "Save" or "Cancel".
HTMX: Server-Driven Swapping
HTMX replaces a div with a form fragment fetched from the server. The entire state transition is managed by server responses.
<!-- HTMX requires a server to serve the edit-form fragment -->
<div id="user-1" hx-target="this" hx-swap="outerHTML">
<strong>Jane Doe</strong>
<button hx-get="/edit-form/1" class="btn">
Edit
</button>
</div>
<!-- On click, the server returns this HTML fragment: -->
<!-- <form hx-put="/user/1">
<input name="name" value="Jane Doe">
<button type="submit">Save</button>
<button hx-get="/user/1">Cancel</button>
</form> -->Invokers: Client-Side State Toggling (No JS, No Server)
Invokers handles this by toggling the visibility of two divs that already exist on the page. It's instantaneous and requires zero network latency or server-side logic for the UI change.
<!-- Invokers handles this entirely on the client, no server needed -->
<div class="user-profile">
<!-- 1. The view state (visible by default) -->
<div id="user-view">
<strong>Jane Doe</strong>
<button type="button" class="btn"
command="--hide" commandfor="user-view"
data-and-then="--show" data-and-then-commandfor="user-edit">
Edit
</button>
</div>
<!-- 2. The edit state (hidden by default) -->
<div id="user-edit" hidden>
<input type="text" value="Jane Doe">
<button type="button" class="btn-primary" command="--emit:save-user:1">Save</button>
<button type="button" class="btn"
command="--hide" commandfor="user-edit"
data-and-then="--show" data-and-then-commandfor="user-view">
Cancel
</button>
</div>
</div>Use Case: Dynamic Content Swapping & Fetching
Replace page sections with new content, either from templates or remote APIs, with precise control over insertion strategy.
HTMX: Server-Driven Content Swapping
HTMX fetches HTML fragments from the server and swaps them into the DOM using hx-swap strategies.
<!-- HTMX requires server endpoints for each content type -->
<div id="content-area">
<button hx-get="/api/widget-a" hx-swap="innerHTML">Load Widget A</button>
<button hx-get="/api/widget-b" hx-swap="outerHTML" hx-target="#content-area">Replace Container</button>
</div>
<!-- Server must return complete HTML fragments -->Invokers: Client-Side DOM Swapping & Fetching Invokers can swap content from local templates or fetch from APIs, with granular control over insertion strategies.
<!-- Templates defined in the same HTML document -->
<template id="widget-a-template">
<div class="widget widget-a">
<h3>Widget A</h3>
<p>This content comes from a local template.</p>
</div>
</template>
<template id="widget-b-template">
<div class="widget widget-b">
<h3>Widget B</h3>
<p>This replaces the entire container.</p>
</div>
</template>
<div id="content-area">
<!-- Swap with local templates using different strategies -->
<button command="--dom:swap" data-template-id="widget-a-template"
commandfor="#content-area" data-replace-strategy="innerHTML">
Load Widget A (Inner)
</button>
<button command="--dom:swap" data-template-id="widget-b-template"
commandfor="#content-area" data-replace-strategy="outerHTML">
Load Widget B (Replace Container)
</button>
<!-- Fetch remote content with precise insertion control -->
<button command="--fetch:get" data-url="/api/sidebar"
commandfor="#content-area" data-replace-strategy="beforeend">
Add Sidebar
</button>
<button command="--fetch:get" data-url="/api/header"
commandfor="#content-area" data-replace-strategy="afterbegin">
Prepend Header
</button>
<!-- Swap only a specific element from the response -->
<button command="--fetch:get" data-url="/posts?page=2"
commandfor="#tbody" data-select="#tbody">
Next Page
</button>
</div>Key Differences:
- Philosophy: HTMX extends HTML as a hypermedia control. Invokers extends HTML for rich, client-side UI interactions.
- Network: HTMX is chatty by design. Invokers is silent unless you explicitly use
--fetch. - State: With HTMX, UI state often lives on the server. With Invokers, UI state lives in the DOM.
- Use Case: HTMX is excellent for server-rendered apps (Rails, Django, PHP). Invokers excels at enhancing static sites, design systems, and front-end frameworks.
vs Alpine.js
Alpine puts JavaScript logic in your HTML; Invokers keeps it out.
Alpine.js gives you framework-like reactivity and state management by embedding JavaScript expressions in x- attributes. Invokers achieves similar results using a predefined set of commands, keeping your markup free of raw JavaScript and closer to standard HTML.
Use Case: Textarea Character Counter
Show a live character count as a user types in a textarea.
Alpine.js: State and Logic in x-data
Alpine creates a small, self-contained component with its own state (message) and uses JS properties (message.length) directly in the markup.
<!-- Alpine puts a "sprinkle" of JavaScript directly in the HTML -->
<div x-data="{ message: '', limit: 140 }">
<textarea x-model="message" :maxlength="limit" class="input"></textarea>
<p class="char-count">
<span x-text="message.length">0</span> / <span x-text="limit">140</span>
</p>
</div>Invokers: Declarative Commands and Expressions
Invokers uses the command-on attribute to listen for the input event and the {{...}} expression engine to update the target's text content. It describes the relationship between elements, not component logic.
<!-- Invokers describes the event and action, no JS logic in the HTML -->
<div>
<textarea id="message-input" maxlength="140" class="input"
command-on="input"
command="--text:set:{{this.value.length}}"
commandfor="char-count"></textarea>
<p class="char-count">
<span id="char-count">0</span> / 140
</p>
</div>Key Differences:
- Syntax: Alpine uses custom JS-like attributes (
x-data,x-text). Invokers uses standard-proposal attributes (command,commandfor) and CSS-like command names (--text:set). - State: Alpine encourages creating explicit state (
x-data). Invokers derives state directly from the DOM (e.g.,this.value.length). - Paradigm: Alpine creates "mini-apps" in your DOM. Invokers creates declarative "event-action" bindings between elements.
- Future: The
commandattribute is on a standards track. Alpine's syntax is specific to the library.
vs Stimulus
Stimulus organizes your JavaScript; Invokers helps you eliminate it.
Stimulus is a modest JavaScript framework that connects HTML to JavaScript objects (controllers). It’s designed for applications with significant custom JavaScript logic. Invokers is designed to handle common UI patterns with no custom JavaScript at all.
Use Case: Copy to Clipboard with Feedback
A user clicks a button to copy a URL to their clipboard, and the button provides feedback by changing its text to "Copied!" for a moment.
Stimulus: HTML Connected to a JS Controller
Stimulus requires a JavaScript controller to hold the logic for interacting with the clipboard API and managing the button's state (text change and timeout). The HTML contains data-* attributes to connect elements to this controller.
<!-- Stimulus connects HTML elements to a required JS controller -->
<div data-controller="clipboard">
<input data-clipboard-target="source" type="text"
value="https://example.com" readonly>
<button data-action="clipboard#copy" class="btn">
Copy Link
</button>
</div>// A "clipboard_controller.js" file is required
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["source"]
copy(event) {
// Logic to interact with the browser API
navigator.clipboard.writeText(this.sourceTarget.value)
// Custom logic for UI feedback
const originalText = event.currentTarget.textContent
event.currentTarget.textContent = "Copied!"
setTimeout(() => {
event.currentTarget.textContent = originalText
}, 2000)
}
}Invokers: Declarative Behavior with Command Chaining
Invokers has a built-in --clipboard:copy command. The UI feedback is handled declaratively by chaining commands in the data-and-then attribute. The entire workflow is defined in a single, readable line with no separate JavaScript file needed.
<!-- Invokers handles this with a single line of chained commands -->
<div>
<input id="share-url" type="text" value="https://example.com" readonly>
<button type="button" class="btn"
command="--clipboard:copy"
commandfor="share-url"
data-and-then="--text:set:Copied!, --command:delay:2000, --text:set:Copy Link">
Copy Link
</button>
</div>(Note: For more robust error handling, you could use data-after-success instead of data-and-then to ensure the feedback only runs if the copy action succeeds.)
Key Differences:
- Ceremony: Stimulus requires a specific file structure and JS classes for every distinct piece of functionality. Invokers requires only HTML attributes for most tasks.
- Source of Truth: In Stimulus, the behavior logic lives in the JS controller. In Invokers, the entire workflow is declared directly in the HTML.
- Goal: Stimulus aims to give structure to complex applications that will inevitably have a lot of custom JS. Invokers aims to prevent you from needing to write JS in the first place for common UI patterns.
- When to Choose: Use Stimulus when you have complex, stateful client-side logic that needs organization. Use Invokers when you want to build interactive UIs quickly with minimal or no JavaScript boilerplate.
Why Invokers?
Write interactive UIs without JavaScript. Invokers transforms static HTML into dynamic, interactive interfaces using declarative attributes. Perfect for progressive enhancement, component libraries, and reducing JavaScript complexity.
<!-- Toggle a menu -->
<button command="--toggle" commandfor="menu">Menu</button>
<nav id="menu" hidden>...</nav>
<!-- Form with dynamic feedback -->
<form command-on="submit.prevent" command="--fetch:send" commandfor="#result">
<input name="query" placeholder="Search...">
<button type="submit">Search</button>
</form>
<div id="result"></div>Modular Architecture
Choose exactly what you need. Invokers now features a hyper-modular architecture with four tiers:
- 🏗️ Tier 0: Core polyfill (25.8 kB) - Standards-compliant foundation
- ⚡ Tier 1: Essential commands (~30 kB) - Basic UI interactions
- 🔧 Tier 2: Specialized packs (25-47 kB each) - Advanced functionality
- 🌟 Tier 3: Reactive engine (26-58 kB) - Dynamic templating & events
Installation & Basic Usage
Core Installation (25.8 kB)
For developers who want just the standards polyfill:
npm install invokersimport 'invokers';
// That's it! Now command/commandfor attributes work<!-- Native/polyfilled commands work immediately -->
<button command="toggle-popover" commandfor="menu">Menu</button>
<div id="menu" popover>Menu content</div>Essential UI Commands (+30 kB)
Add the most common interactive commands:
import invokers from 'invokers';
import { registerBaseCommands } from 'invokers/commands/base';
import { registerFormCommands } from 'invokers/commands/form';
registerBaseCommands(invokers);
registerFormCommands(invokers);<!-- Now you can use essential commands -->
<button command="--toggle" commandfor="sidebar">Toggle Sidebar</button>
<button command="--class:toggle:dark-mode" commandfor="body">Dark Mode</button>
<button command="--text:set:Hello World!" commandfor="output">Set Text</button>Advanced Applications (+140 kB)
For complex applications with reactive state, advanced control flow, and comprehensive form handling, import the additional modules:
import 'invokers'; // Core polyfill
import { enableState } from 'invokers/state';
import { enableControl } from 'invokers/control';
import { enableForms } from 'invokers/forms';
enableState(); // Reactive state management
enableControl(); // Advanced control flow
enableForms(); // Enterprise form handlingOptional Enhancements: Anchor Invokers
Enable progressive enhancement for anchors so href can be used with commandfor and optional data-select attributes.
import { enableAnchorInvokers } from 'invokers/anchors';
enableAnchorInvokers();<a href="/posts?page=2" commandfor="#tbody" data-select="#tbody">
Next Page
</a>For custom elements, register a InvokerAdapter via registerInvokerAdapter and call enableAdapterInvokers from the same module.
Command Packs
Tier 1: Essential Commands
Base Commands (invokers/commands/base) - 29.2 kB
Essential UI state management without DOM manipulation.
import { registerBaseCommands } from 'invokers/commands/base';
registerBaseCommands(invokers);Commands: --toggle, --show, --hide, --class:*, --attr:*
<button command="--toggle" commandfor="menu">Menu</button>
<button command="--class:add:active" commandfor="tab1">Activate Tab</button>
<button command="--attr:set:aria-expanded:true" commandfor="dropdown">Expand</button>Form Commands (invokers/commands/form) - 30.5 kB
Form interactions and content manipulation.
import { registerFormCommands } from 'invokers/commands/form';
registerFormCommands(invokers);Commands: --text:*, --value:*, --focus, --disabled:*, --form:*, --input:step
<button command="--text:set:Form submitted!" commandfor="status">Submit</button>
<button command="--value:set:[email protected]" commandfor="email">Use Admin Email</button>
<button command="--input:step:5" commandfor="quantity">+5</button>Tier 2: Specialized Commands
DOM Manipulation (invokers/commands/dom) - 47.1 kB
Dynamic content insertion and templating.
import { registerDomCommands } from 'invokers/commands/dom';
registerDomCommands(invokers);Commands: --dom:*, --template:*
<button command="--dom:append" commandfor="list" data-template-id="item-tpl">Add Item</button>
<button command="--template:render:user-card" commandfor="output"
data-name="John" data-email="[email protected]">Render User</button>Flow Control (invokers/commands/flow) - 45.3 kB
Async operations, navigation, and data binding.
import { registerFlowCommands } from 'invokers/commands/flow';
registerFlowCommands(invokers);Commands: --fetch:*, --navigate:*, --emit:*, --command:*, --bind:*
<!-- Basic fetch with replace strategies -->
<button command="--fetch:get" data-url="/api/users" commandfor="user-list"
data-replace-strategy="innerHTML">Load Users</button>
<!-- Form submission with custom replace strategy -->
<form id="contact-form" action="/api/contact" method="post"></form>
<button command="--fetch:send" commandfor="contact-form"
data-response-target="#response"
data-replace-strategy="outerHTML">Send Message</button>
<button command="--navigate:to:/dashboard">Go to Dashboard</button>
<input id="bind-input" command-on="input" command="--bind:value" commandfor="bind-input" data-bind-to="#output" data-bind-as="text">Replace Strategies:
innerHTML(default): Replace target element's contentouterHTML: Replace entire target elementbeforebegin/afterbegin/beforeend/afterend: Insert adjacent to target
Selection Options (HTML responses):
data-select: Replace with the first matching element from the responsedata-select-all: Replace with all matching elements from the response
Media & Animation (invokers/commands/media) - 27.7 kB
Rich media controls and interactions.
import { registerMediaCommands } from 'invokers/commands/media';
registerMediaCommands(invokers);Commands: --media:*, --carousel:*, --scroll:*, --clipboard:*
<button command="--media:toggle" commandfor="video">Play/Pause</button>
<button command="--carousel:nav:next" commandfor="slideshow">Next</button>
<button command="--scroll:to" commandfor="section2">Scroll to Section</button>
<button command="--clipboard:copy" commandfor="code">Copy Code</button>Browser APIs (invokers/commands/browser) - 25.3 kB
Cookie management and browser integration.
import { registerBrowserCommands } from 'invokers/commands/browser';
registerBrowserCommands(invokers);Commands: --cookie:*
<button command="--cookie:set:theme:dark" data-cookie-expires="365">Set Dark Theme</button>
<button command="--cookie:get:theme" commandfor="current-theme">Show Theme</button>Data Management (invokers/commands/data) - 45.2 kB
Complex data operations and array manipulation.
import { registerDataCommands } from 'invokers/commands/data';
registerDataCommands(invokers);Commands: --data:*, array operations, reactive data binding
<button command="--data:set:userId:123" commandfor="profile">Set User ID</button>
<button command="--data:set:array:push:todos" data-value='{"title":"New Task"}'
commandfor="app">Add Todo</button>Device APIs (invokers/commands/device) - 28.1 kB
import { registerDeviceCommands } from 'invokers/commands/device';
registerDeviceCommands(invokers);Commands: --device:vibrate, --device:share, --device:geolocation:get, --device:battery:get, --device:clipboard:*, --device:wake-lock*
<button command="--device:vibrate:200:100:200">Vibrate</button>
<button command="--device:share:title:Check this out:text:Amazing content:url:https://example.com">Share</button>
<button command="--device:geolocation:get" commandfor="location-display">Get Location</button>Accessibility Helpers (invokers/commands/accessibility) - 26.8 kB
import { registerAccessibilityCommands } from 'invokers/commands/accessibility';
registerAccessibilityCommands(invokers);Commands: --a11y:announce, --a11y:focus, --a11y:skip-to, --a11y:focus-trap, --a11y:aria:*, --a11y:heading-level
<button command="--a11y:announce:Item saved successfully">Save</button>
<button command="--a11y:focus" commandfor="search-input">Focus Search</button>
<button command="--a11y:focus-trap:enable" commandfor="modal">Open Modal</button>Command Cheatsheet
Native Browser Commands (No -- Prefix)
These commands are built into modern browsers and work without any JavaScript framework. Invokers provides full polyfill support for cross-browser compatibility.
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| step-up | Increment number input by step | command="step-up" commandfor="counter" |
| step-down | Decrement number input by step | command="step-down" commandfor="counter" |
| show-modal | Open modal dialog | command="show-modal" commandfor="dialog" |
| close | Close dialog/popover | command="close" commandfor="dialog" |
| toggle-popover | Toggle popover visibility | command="toggle-popover" commandfor="menu"|
| show-picker | Show input picker (date, color) | command="show-picker" commandfor="date" |
| play-pause | Toggle media play/pause | command="play-pause" commandfor="video" |
| toggle-muted | Toggle media mute state | command="toggle-muted" commandfor="video" |
| toggle-fullscreen | Toggle fullscreen mode | command="toggle-fullscreen" |
| copy-text | Copy text to clipboard | command="copy-text" commandfor="source" |
| share | Share content via Web Share API | command="share" commandfor="content" |
Core Commands (Available Now)
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --toggle | Show/hide + update ARIA | command="--toggle" commandfor="menu" |
| --show | Show one, hide siblings | command="--show" commandfor="panel-1" |
| --hide | Hide element | command="--hide" commandfor="alert" |
| --class:add:name | Add CSS class | command="--class:add:active" |
| --class:remove:name | Remove CSS class | command="--class:remove:loading" |
| --class:toggle:name | Toggle CSS class | command="--class:toggle:dark-mode" |
| --text:set:message | Replace text content | command="--text:set:Hello World" |
| --text:append:text | Append to text content | command="--text:append: more text" |
| --text:prepend:text | Prepend to text content | command="--text:prepend:Prefix " |
| --text:clear | Clear text content | command="--text:clear" |
| --attr:set:name:val | Set attribute | command="--attr:set:disabled:true" |
| --attr:remove:name | Remove attribute | command="--attr:remove:disabled" |
| --attr:toggle:name | Toggle attribute presence | command="--attr:toggle:hidden" |
| --value:set | Set input value | command="--value:set:new-value" |
| --focus | Focus element | command="--focus" commandfor="input" |
| --disabled:toggle | Toggle disabled state | command="--disabled:toggle" |
| --scroll:into-view | Scroll element into view | command="--scroll:into-view" |
| --scroll:top | Scroll to top of element | command="--scroll:top" |
| --scroll:bottom | Scroll to bottom of element | command="--scroll:bottom" |
| --scroll:center | Scroll to center of element | command="--scroll:center" |
Storage Commands
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --storage:local:set:key:val | Store in localStorage | command="--storage:local:set:user:name" |
| --storage:session:set:key:val | Store in sessionStorage | command="--storage:session:set:temp:data" |
| --storage:local:get:key | Get from localStorage | command="--storage:local:get:user" |
| --storage:local:remove:key | Remove from localStorage | command="--storage:local:remove:user" |
| --storage:local:clear | Clear all localStorage | command="--storage:local:clear" |
| --storage:local:keys | Get all localStorage keys | command="--storage:local:keys" |
| --storage:local:has:key | Check if key exists | command="--storage:local:has:user" |
| --storage:local:size | Get localStorage size in bytes | command="--storage:local:size" |
Animation Commands
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --animate:fade-in | Fade element in | command="--animate:fade-in" |
| --animate:fade-out | Fade element out | command="--animate:fade-out" |
| --animate:slide-up | Slide up animation | command="--animate:slide-up" |
| --animate:slide-down | Slide down animation | command="--animate:slide-down" |
| --animate:bounce | Bounce animation | command="--animate:bounce" |
| --animate:spin | Spin animation | command="--animate:spin" |
Event Commands
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --emit:event-name | Dispatch custom event | command="--emit:my-event:detail-data" |
URL Manipulation Commands
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --url:params-get:key | Get URL parameter | command="--url:params-get:id" |
| --url:params-set:key:val | Set URL parameter | command="--url:params-set:page:2" |
| --url:params-set:key | Set URL parameter from input | command="--url:params-set:query" commandfor="search-input" |
| --url:params-delete:key | Delete URL parameter | command="--url:params-delete:id" |
| --url:params-clear | Clear all URL parameters | command="--url:params-clear" |
| --url:params-all | Get all URL parameters as JSON | command="--url:params-all" |
| --url:hash-get | Get URL hash | command="--url:hash-get" |
| --url:hash-set:value | Set URL hash | command="--url:hash-set:section-1" |
| --url:hash-set | Set URL hash from input | command="--url:hash-set" commandfor="hash-input" |
| --url:hash-clear | Clear URL hash | command="--url:hash-clear" |
| --url:pathname-get | Get current pathname | command="--url:pathname-get" |
| --url:pathname-set:path | Set pathname | command="--url:pathname-set:/new-page" |
| --url:pathname-set | Set pathname from input | command="--url:pathname-set" commandfor="path-input" |
| --url:reload | Reload the page | command="--url:reload" |
| --url:replace:url | Replace current URL | command="--url:replace:/new-page" |
| --url:navigate:url | Navigate to URL | command="--url:navigate:/new-page" |
| --url:base | Get base URL (protocol+host) | command="--url:base" |
| --url:full | Get full current URL | command="--url:full" |
Input/Textarea Integration: URL commands like params-set, hash-set, and pathname-set can get their values from <input> or <textarea> elements by using commandfor to target the input element. If no value is provided in the command string, the value will be taken from the target element's value property.
History Commands
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --history:push:url | Push new history entry | command="--history:push:/new-page" |
| --history:replace:url| Replace current history entry | command="--history:replace:/new-page" |
| --history:back | Go back in history | command="--history:back" |
| --history:forward | Go forward in history | command="--history:forward" |
| --history:go:delta | Go to specific history position | command="--history:go:-2" |
| --history:state:get | Get current history state | command="--history:state:get" |
| --history:state:set:data | Set history state | command="--history:state:set:json-data" |
| --history:length | Get history length | command="--history:length" |
| --history:clear | Clear history state | command="--history:clear" |
Device API Commands
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --device:vibrate:pattern | Vibrate device | command="--device:vibrate:200:100:200" |
| --device:share:url:text:title | Share content | command="--device:share:url:http://ex.com" |
| --device:geolocation:get | Get device location | command="--device:geolocation:get" |
| --device:battery:get | Get battery status | command="--device:battery:get" |
| --device:clipboard:read | Read from clipboard | command="--device:clipboard:read" |
| --device:clipboard:write:text | Write to clipboard | command="--device:clipboard:write:hello" |
| --device:wake-lock | Request wake lock | command="--device:wake-lock" |
| --device:wake-lock:release | Release wake lock | command="--device:wake-lock:release" |
Accessibility Commands
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --a11y:announce:text | Announce to screen readers | command="--a11y:announce:Item saved" |
| --a11y:focus | Focus element with announcement | command="--a11y:focus" commandfor="input" |
| --a11y:skip-to:id | Skip navigation to element | command="--a11y:skip-to:main-content" |
| --a11y:focus-trap:enable | Enable focus trap | command="--a11y:focus-trap:enable" |
| --a11y:aria:set:attr:val | Set ARIA attribute | command="--a11y:aria:set:label:Save button"|
| --a11y:aria:remove:attr | Remove ARIA attribute | command="--a11y:aria:remove:label" |
| --a11y:heading-level:level | Set heading level | command="--a11y:heading-level:2" |
Extended Commands (Auto-Included)
| Command | Purpose | Example |
| ---------------------- | --------------------------------- | -------------------------------------------- |
| --media:toggle | Toggle play/pause | command="--media:toggle" commandfor="video"|
| --media:seek:seconds | Seek media by seconds | command="--media:seek:10" |
| --media:mute | Toggle media mute | command="--media:mute" |
| --carousel:nav:next | Navigate carousel | command="--carousel:nav:next" |
| --clipboard:copy | Copy text to clipboard | command="--clipboard:copy" |
| --form:reset | Reset form | command="--form:reset" |
| --form:submit | Submit form | command="--form:submit" |
| --input:step:amount | Step number input | command="--input:step:1" |
| --dom:remove | Remove element from DOM | command="--dom:remove" |
| --dom:clear | Remove all child nodes | command="--dom:clear" |
| --dom:replace[:inner\:outer] | Replace with template content (inner/outer) | command="--dom:replace:outer" data-template-id="tpl" |
| --dom:swap[:inner\:outer] | Swap content with template (inner/outer) | command="--dom:swap:outer" data-template-id="tpl"|
| --dom:append[:inner\:outer] | Append template content (inner/outer) | command="--dom:append:outer" data-template-id="tpl" |
| --dom:prepend[:inner\:outer] | Prepend template content (inner/outer) | command="--dom:prepend:outer" data-template-id="tpl" |
| --dom:wrap[:tag] | Wrap element with template/tag | command="--dom:wrap:div" data-wrapper-class="card" |
| --dom:unwrap | Unwrap element from parent | command="--dom:unwrap" |
| --dom:toggle-empty-class:class | Toggle class based on children | command="--dom:toggle-empty-class:empty" |
| --data:set:key:val | Set data attribute on element | command="--data:set:userId:123" |
| --data:copy:key | Copy data attribute between elements | command="--data:copy:userId" data-copy-from="#src" |
| --cookie:set:key:val | Set browser cookie | command="--cookie:set:theme:dark" |
| --cookie:get:key | Get cookie value | command="--cookie:get:theme" |
| --cookie:remove:key | Remove browser cookie | command="--cookie:remove:theme" |
| --command:trigger:event | Trigger event on element | command="--command:trigger:click" commandfor="#btn" |
| --command:delay:ms | Wait for milliseconds | command="--command:delay:2000" |
| --on:interval:ms | Execute command at intervals | command-on="load" command="--on:interval:5000" data-interval-command="--fetch:get" |
| --bind:prop | Bind data between elements | command="--bind:value" commandfor="source" data-bind-to="#output" |
| --text:copy | Copy text between elements | command="--text:copy" data-copy-from="#source" |
| --fetch:get | GET request (HTML/JSON/text) | command="--fetch:get" data-url="/api/data" data-response-type="json" |
| --fetch:post | POST request with body | command="--fetch:post" data-url="/api/users" data-body='{"name":"John"}' |
| --fetch:put | PUT request for full updates | command="--fetch:put" data-url="/api/users/1" data-body='{...}' |
| --fetch:patch | PATCH request for partial updates | command="--fetch:patch" data-url="/api/users/1" data-body='{...}' |
| --fetch:delete | DELETE request | command="--fetch:delete" data-url="/api/users/1" |
| --fetch:head | HEAD request (headers only) | command="--fetch:head" data-url="/api/resource" |
| --fetch:options | OPTIONS request (CORS checks) | command="--fetch:options" data-url="/api/users" |
| --fetch:send | Send form data via fetch | command="--fetch:send" commandfor="my-form" |
| --navigate:to:url | Navigate using History API | command="--navigate:to:/new-page" |
Native/Polyfilled Commands (No -- Prefix)
| Command | Target Element | Purpose |
| ---------------------- | -------------------- | -------------------------------------------- |
| show-modal | <dialog> | Open dialog modally |
| close | <dialog>, <popover> | Close dialog/popover |
| request-close | <dialog> | Request dialog close (allows cancel) |
| toggle-popover | <popover> | Toggle popover visibility |
| show-popover | <popover> | Show popover |
| hide-popover | <popover> | Hide popover |
| toggle | <details> | Toggle details open/closed |
| open | <details> | Open details element |
| show-picker | <input>, <select>| Show native picker (date, file, etc.) |
| play-pause | <video>, <audio> | Toggle media playback |
| play | <video>, <audio> | Start media playback |
| pause | <video>, <audio> | Pause media playback |
| toggle-muted | <video>, <audio> | Toggle media mute state |
| toggle-fullscreen | Any element | Toggle fullscreen mode |
| request-fullscreen | Any element | Enter fullscreen mode |
| exit-fullscreen | Any element | Exit fullscreen mode |
| copy-text | Any element | Copy element's text to clipboard |
| share | Any element | Share element's text or URL |
| step-up | <input type=number>| Increment number input |
| step-down | <input type=number>| Decrement number input |
| toggle-openable | Openable elements | Toggle open/close state |
| open-openable | Openable elements | Open element |
| close-openable | Openable elements | Close element |
Real-time Communication Commands
| Command | Purpose | Example |
| ---------------------- | -------------------------------------------- | -------------------------------------------- |
| --websocket:connect | Establish WebSocket connection | command="--websocket:connect" data-url="wss://api.example.com" |
| --websocket:disconnect| Close WebSocket connection | command="--websocket:disconnect" |
| --websocket:send:message| Send message via WebSocket | command="--websocket:send:Hello World" |
| --websocket:status | Get WebSocket connection status | command="--websocket:status" |
| --websocket:on:message| Handle incoming WebSocket messages | command="--websocket:on:message" data-message-command="--text:append" |
| --websocket:on:open | Handle WebSocket connection opened | command="--websocket:on:open" data-open-command="--class:add:connected" |
| --websocket:on:close | Handle WebSocket connection closed | command="--websocket:on:close" data-close-command="--class:remove:connected" |
| --websocket:on:error | Handle WebSocket connection errors | command="--websocket:on:error" data-error-command="--text:set:Connection failed" |
| --sse:connect | Establish Server-Sent Events connection | command="--sse:connect" data-url="/api/events" |
| --sse:disconnect | Close SSE connection | command="--sse:disconnect" |
| --sse:status | Get SSE connection status | command="--sse:status" |
| --sse:on:message | Handle incoming SSE messages | command="--sse:on:message" data-message-command="--text:append" |
| --sse:on:event:type | Handle specific SSE event types | command="--sse:on:event:user-joined" data-event-command="--text:append" |
Pipeline Commands
| Command | Purpose | Example |
| ---------------------- | -------------------------------------------- | -------------------------------------------- |
| --pipeline:execute:id| Execute template-based command pipeline | command="--pipeline:execute:user-flow" |
💡 Tip: Commands starting with -- are Invokers extensions. Commands without prefixes are native/future browser commands.
Command Syntax Guide
Parameter Syntax
Commands use colon (:) separated parameters:
<!-- Basic parameter -->
<button command="--text:set:Hello World">Set Text</button>
<!-- Multiple parameters -->
<button command="--storage:local:set:user:John">Save User</button>
<!-- Numeric parameters -->
<button command="--media:seek:30">Skip 30s</button>Data Attributes for Enhanced Control
Many commands support additional configuration via data-* attributes:
Fetch Commands
All HTTP verbs are supported with comprehensive configuration options:
<!-- GET request with HTML response -->
<button type="button"
command="--fetch:get"
data-url="/api/data"
data-response-type="html"
data-replace-strategy="innerHTML"
data-loading-template="spinner"
data-error-template="error-msg"
data-response-target="#result"
commandfor="content-area">
Load HTML
</button>
<!-- POST request with JSON body and headers -->
<button type="button"
command="--fetch:post"
data-url="/api/users"
data-body='{"name":"John","email":"[email protected]"}'
data-header-content-type="application/json"
data-header-authorization="Bearer token123"
data-response-type="json"
commandfor="result">
Create User
</button>
<!-- PUT request with body from form -->
<form id="user-form">
<input name="name" value="Jane">
<input name="email" value="[email protected]">
</form>
<button type="button"
command="--fetch:put"
data-url="/api/users/123"
data-body-from="#user-form"
commandfor="result">
Update User
</button>
<!-- DELETE request with CORS credentials -->
<button type="button"
command="--fetch:delete"
data-url="/api/users/123"
data-credentials="include"
data-mode="cors"
data-header-authorization="Bearer token123"
data-after-success="--dom:remove"
commandfor="user-123">
Delete User
</button>
<!-- HEAD request to check resource -->
<button type="button"
command="--fetch:head"
data-url="/api/large-file"
commandfor="file-info">
Check File
</button>Fetch Data Attributes:
data-url- Request URL (required)data-response-type- Response format:html,json,text,headers(default:html)data-replace-strategy- Where to insert:innerHTML,outerHTML,beforebegin,afterbegin,beforeend,afterend(default:innerHTML)data-body- Inline request body (for POST/PUT/PATCH)data-body-from- Selector to get body from form/input/elementdata-header-*- Custom headers (e.g.,data-header-authorization="Bearer token")data-response-target- Alternative target for responsedata-loading-template- Template to show while loadingdata-error-template- Template to show on errordata-credentials- CORS credentials:omit,same-origin,includedata-mode- CORS mode:cors,no-cors,same-origindata-timeout- Request timeout in milliseconds (default: 30000)
#### Animation Commands
```html
<button type="button"
command="--animate:fade-in"
data-animate-duration="2s"
data-animate-delay="500ms"
data-animate-easing="ease-out"
data-animate-iterations="3">
Custom Fade In
</button>Storage Commands
<button type="button"
command="--storage:local:set:settings"
data-storage-json="true"
data-storage-expires="3600">
Save Settings (JSON, expires in 1 hour)
</button>Device Commands
<button type="button"
command="--device:geolocation:get"
data-geo-high-accuracy="true"
data-geo-timeout="10000"
data-geo-max-age="300000">
Get Location
</button>Error Handling
Commands include comprehensive error handling with helpful messages:
- Validation errors for incorrect parameters
- Permission errors for device APIs requiring user consent
- Network errors for fetch operations
- Browser support warnings for unsupported features
Errors are logged to console with recovery suggestions. Use browser dev tools to see detailed error information.
Command States
Control command execution behavior with data-state:
<!-- Execute once, then disable -->
<button command="--show" commandfor="welcome" data-state="once">Show Welcome</button>
<!-- Currently disabled -->
<button command="--toggle" commandfor="menu" data-state="disabled">Menu</button>
<!-- Completed, won't execute again -->
<button command="--fetch:get" data-url="/api" data-state="completed">Load Data</button>Tier 3: Advanced Features
Event Triggers (invokers/advanced/events) - 42.3 kB
Advanced event binding with command-on attribute.
import { enableEventTriggers } from 'invokers/advanced/events';
enableEventTriggers();<!-- Respond to any DOM event -->
<form command-on="submit.prevent" command="--fetch:send" commandfor="result">...</form>
<input command-on="input" command="--text:set:{{this.value}}" commandfor="preview">Expression Engine (invokers/advanced/expressions) - 58.3 kB
Dynamic templating with {{expression}} syntax and 40+ built-in helper functions.
import { enableExpressionEngine } from 'invokers/advanced/expressions';
enableExpressionEngine(); // Full expressions with all helpers<!-- Dynamic command parameters -->
<button command="--text:set:Hello {{user.name}}!" commandfor="greeting">Greet</button>
<button command="--class:toggle:{{this.dataset.theme}}-mode" commandfor="body">Theme</button>Modular Expression Helpers - Optimize Bundle Size
Import only the expression helpers you need to reduce bundle size by up to 7.7 kB:
Core Expressions Only (50.6 kB)
For applications that only need basic expressions without helper functions:
import 'invokers'; // 25.8 kB
import { enableExpressionEngine } from 'invokers/advanced/expressions/core'; // +50.6 kB
// Total: 76.4 kB (vs 84.1 kB with full expressions)
enableExpressionEngine();<!-- Basic expressions work -->
<button command="--text:set:{{1 + 2 * 3}}" commandfor="result">Calculate</button>
<button command="--class:toggle:{{active ? 'enabled' : 'disabled'}}" commandfor="button">Toggle</button>Selective Helper Categories
Add only the helper functions you need:
import 'invokers'; // 25.8 kB
import { enableExpressionEngine } from 'invokers/advanced/expressions/core'; // +50.6 kB
import { enableStringHelpers } from 'invokers/advanced/expressions/helpers/string'; // +1.22 kB
import { enableMathHelpers } from 'invokers/advanced/expressions/helpers/math'; // +859 B
// Total: 78.48 kB (vs 84.1 kB with all helpers)
enableExpressionEngine();
enableStringHelpers();
enableMathHelpers();Available Helper Categories:
- String Helpers (
1.22 kB):concat,uppercase,lowercase,trim,capitalize,replace,substring,truncate,pluralize - Array Helpers (
1.94 kB):randomChoice,arrayLength,arrayMap,arrayFilter,join,filter,sort - Math Helpers (
859 B):random,randomInt,floor,ceil,round,min,max,pow,sqrt,clamp - Date Helpers (
741 B):now,formatDate,timeAgo - Utility Helpers (
1.62 kB):formatNumber,formatCurrency,isEmpty,typeof,isArray,coalesce
Real-World Examples
String-Heavy Application:
import { enableExpressionEngine } from 'invokers/advanced/expressions/core';
import { enableStringHelpers } from 'invokers/advanced/expressions/helpers/string';
enableExpressionEngine();
enableStringHelpers();<!-- String manipulation -->
<div>{{concat(firstName, " ", lastName)}}</div>
<div>{{uppercase(jobTitle)}}</div>
<div>{{truncate(description, 100)}}</div>Math/Data Application:
import { enableExpressionEngine } from 'invokers/advanced/expressions/core';
import { enableMathHelpers } from 'invokers/advanced/expressions/helpers/math';
import { enableArrayHelpers } from 'invokers/advanced/expressions/helpers/array';
enableExpressionEngine();
enableMathHelpers();
enableArrayHelpers();<!-- Math and array operations -->
<span>{{round(price * 1.08)}}</span>
<div>{{arrayLength(items)}} items</div>
<div>{{join(selectedTags, ", ")}}</div>Form Validation Application:
import { enableExpressionEngine } from 'invokers/advanced/expressions/core';
import { enableUtilityHelpers } from 'invokers/advanced/expressions/helpers/utility';
import { enableStringHelpers } from 'invokers/advanced/expressions/helpers/string';
enableExpressionEngine();
enableUtilityHelpers();
enableStringHelpers();<!-- Validation and formatting -->
<div class="{{isEmpty(email) ? 'error' : 'valid'}}">
{{isEmpty(email) ? 'Email required' : 'Valid email'}}
</div>
<div>{{formatCurrency(total)}}</div>Advanced: Direct Helper Import
For maximum control, import helpers directly:
import { stringHelpers } from 'invokers/advanced/expressions/helpers/string';
import { mathHelpers } from 'invokers/advanced/expressions/helpers/math';
// Register only specific functions
registerExpressionFunction({
name: 'customConcat',
implementation: (...args) => args.join('-')
});Bundle Size Comparison
| Configuration | Bundle Size | Savings | |---------------|-------------|---------| | Full expressions | 84.1 kB | - | | Core only | 76.4 kB | 7.7 kB | | + String helpers | 77.62 kB | 6.48 kB | | + Math helpers | 77.26 kB | 6.84 kB | | + Array helpers | 78.34 kB | 5.76 kB | | + Date helpers | 77.14 kB | 6.96 kB | | + Utility helpers | 78.02 kB | 6.08 kB |
Complete Advanced Features (invokers/advanced) - 42.4 kB
Both event triggers and expressions in one import.
import { enableAdvancedEvents } from 'invokers/advanced';
enableAdvancedEvents();<!-- Fully dynamic interactions -->
<form command-on="submit.prevent"
command="--text:set:Submitted {{this.elements.name.value}}"
commandfor="status">
<input name="name" placeholder="Your name">
<button type="submit">Submit</button>
</form>Comprehensive Demo
For a deeper dive into Invokers' capabilities, check out our comprehensive demo that showcases:
- Advanced Event Handling with
command-onand dynamic interpolation - Async Operations with promises, error handling, and loading states
- Component Communication through data binding and custom events
- Library Integration with Chart.js and external APIs
- Advanced Templating with loops, conditionals, and data injection
- Programmatic Triggering using the JavaScript API
- Error Handling & Debugging with detailed logging and recovery
- Command Queuing for sequential execution
The demo uses demo-specific commands that are separate from the core library. To use them in your own projects:
import 'invokers'; // Core library
import { registerDemoCommands } from 'invokers/demo-commands';
registerDemoCommands(); // Only for demos/testingOpen examples/comprehensive-demo.html in your browser to explore all features interactively.
Quick Start Examples
Simple Tab System
import invokers from 'invokers';
import { registerBaseCommands } from 'invokers/commands/base';
registerBaseCommands(invokers);<div role="tablist">
<button command="--show" commandfor="tab1" role="tab">Tab 1</button>
<button command="--show" commandfor="tab2" role="tab">Tab 2</button>
</div>
<div id="tab1" role="tabpanel">Content 1</div>
<div id="tab2" role="tabpanel" hidden>Content 2</div>Dynamic Form with Validation
import invokers from 'invokers';
import { registerFormCommands } from 'invokers/commands/form';
import { registerFlowCommands } from 'invokers/commands/flow';
import { enableAdvancedEvents } from 'invokers/advanced';
registerFormCommands(invokers);
registerFlowCommands(invokers);
enableAdvancedEvents();<form command-on="submit.prevent" command="--fetch:send" commandfor="contact-result" data-url="/api/contact"