npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

Readme

npm version License: MIT Ask DeepWiki

✨ 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

Features

  • Standards-First: Built on the W3C/WHATWG command attribute 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-then attributes 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, and completed for 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 interestfor attribute.
  • 🚀 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

  • command attribute: Specifies the action to perform (e.g., show-modal, toggle-popover)
  • commandfor attribute: References the target element by ID
  • CommandEvent: 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-on attribute for any DOM event (click, input, submit, etc.)
  • Expression Engine: Adds {{...}} syntax for dynamic command parameters
  • Command Chaining: Adds <and-then> elements and data-and-then attributes for workflow orchestration
  • Conditional Logic: Adds success/error state handling with data-after-success/data-after-error
  • Lifecycle States: Adds once, disabled, completed states 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

  • interestfor attribute: 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-source and :interest-target for 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 HTMLElement types (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-end CSS properties
  • Styling Hooks: Adds interest-source/interest-target classes 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-popover work natively
  • ARIA Management: Automatic aria-expanded and aria-details attributes
  • 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:

  1. Invokers will automatically detect native support
  2. Polyfill behaviors will gracefully disable
  3. Your HTML markup remains unchanged
  4. 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 command attribute 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 invokers
import '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 handling

Optional 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 content
  • outerHTML: Replace entire target element
  • beforebegin/afterbegin/beforeend/afterend: Insert adjacent to target

Selection Options (HTML responses):

  • data-select: Replace with the first matching element from the response
  • data-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/element
  • data-header-* - Custom headers (e.g., data-header-authorization="Bearer token")
  • data-response-target - Alternative target for response
  • data-loading-template - Template to show while loading
  • data-error-template - Template to show on error
  • data-credentials - CORS credentials: omit, same-origin, include
  • data-mode - CORS mode: cors, no-cors, same-origin
  • data-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-on and 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/testing

Open 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"