Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.kodexa.ai/llms.txt

Use this file to discover all available pages before exploring further.

V2 data forms can declare keyboard shortcuts as a top-level array on the schema. Each entry binds a key combination to a named script and is registered under a per-form scope, so a form effectively resets all of its shortcuts every time it mounts — you never have to manually un-register them.

Why declarative

Shortcuts live in the schema next to scripts and bridge. The form author writes a key → script mapping; the platform handles registration, scoping, and cleanup. Because each shortcut points at a named script, the same script can be invoked via a hotkey, a button click, a trigger, or a service-bridge response without duplicating code.

Schema

Add a shortcuts array to the form’s top-level definition:
version: "2"
bridge:
  permissions: ["data:read", "navigation"]
shortcuts:
  - key: "control+1"
    description: "Jump to the invoice page"
    group: "navigation"
    scriptRef: gotoInvoice
  - key: "control+f"
    altKey: "meta+f"
    description: "Focus the total field"
    scriptRef: focusTotal
scripts:
  gotoInvoice: |
    (ctx, bridge) => bridge.navigation.setPage(1)
  focusTotal: |
    (ctx, bridge) => bridge.navigation.focusAttribute(
      ctx.dataObjects[0]?.uuid,
      "invoice/total"
    )
nodes:
  - component: v2:panel
    # ...

FormShortcut Fields

FieldTypeRequiredDescription
keystringYesPrimary binding (e.g. "control+1", "meta+shift+s")
altKeystring | string[]NoOne or more alternative bindings that also fire the script
descriptionstringYesLabel shown in the keyboard-shortcuts help dialog (⌘/)
groupstringNoHelp-dialog group: "navigation", "zoom", "data-entry", "document", or "ui"
scriptRefstringYesName of a script in the form’s scripts map to invoke

Lifecycle and scoping

Every shortcut is registered under the scope form:<viewId>. The platform:
  1. On mount — clears the scope (so a stale registration from a previous mount is gone), then registers each entry under the scope.
  2. On shortcuts change — runs the same clear-then-register cycle automatically. Hot-reloading a form during development replaces the bindings cleanly.
  3. On unmount — clears the scope. Shortcuts from other forms or the global help dialog are untouched.
Because scopes are isolated, two open forms can register the same key in different ways — the binding effective at any moment is the one belonging to the most recently mounted form for that key.
If your form’s key collides with a global shortcut already in the help dialog (for example meta+/), the existing global binding wins and the form’s is silently dropped. Prefer keys not used globally.

Inside the script

Scripts referenced by scriptRef follow the standard V2 signature — a function of (ctx, bridge):
(ctx, bridge) => {
  // ctx exposes the form's data context plus a `shortcut` payload
  // describing the FormShortcut entry that fired this invocation.
  bridge.log.debug("Triggered by " + ctx.shortcut.key);

  // bridge.* gives you the same Bridge API documented under
  // "Bridge API & External Services".
  bridge.navigation.setPage(1);
}
The ctx.shortcut payload ({ key, description, scriptRef, ... }) is added by the shortcut dispatcher so a single script can branch on which binding fired it.

What scripts typically do

The most common actions a shortcut performs are spatial navigation, attribute focus, and data-object manipulation — all available through the bridge:
// Jump the spatial viewer to a known page
bridge.navigation.setPage(3);

// Focus a specific field and highlight its tag in the document
bridge.navigation.focusAttribute(parentUuid, "shipment/originZip");

// Read the current page so a shortcut can "go to next page in this group"
const current = bridge.navigation.getCurrentPage();
const total = bridge.navigation.getPageCount();
if (current && current < total) bridge.navigation.setPage(current + 1);

// Add a child data object under a known parent
const obj = await bridge.data.addDataObject(parentUuid, "LineItem");
bridge.data.setAttribute(obj.uuid, "LineItem/Description", "New line");
See Bridge API & External Services for the full method surface.

Permissions

Shortcut scripts call the same Bridge API as any other V2 script, so they obey the same bridge.permissions contract. A shortcut that calls bridge.navigation.setPage(...) needs "navigation" in the form’s permissions array; one that calls bridge.data.addDataObject(...) needs "data:write". Permission errors surface to the browser console and the shortcut becomes a no-op.

Help dialog

Registered shortcuts appear in the global keyboard-shortcuts help dialog (open with ⌘/ on Mac or Ctrl+/ on Windows/Linux), grouped by the optional group field. Use a clear description — that’s what users will see when they’re hunting for a key.

Example: invoice review form

A reviewer-oriented form that binds the number keys to the document’s classification groups and uses Tab-like flow to move between common fields:
version: "2"
bridge:
  permissions: ["data:read", "data:write", "navigation"]
shortcuts:
  - key: "control+1"
    description: "Jump to Invoice"
    group: "navigation"
    scriptRef: gotoInvoice
  - key: "control+2"
    description: "Jump to Bill of Lading"
    group: "navigation"
    scriptRef: gotoBOL
  - key: "control+t"
    description: "Focus invoice total"
    group: "data-entry"
    scriptRef: focusTotal
  - key: "control+n"
    description: "Add a line item"
    group: "data-entry"
    scriptRef: addLineItem
scripts:
  gotoInvoice: |
    (ctx, bridge) => bridge.navigation.setPage(
      ctx.invoicePage ?? 1
    )
  gotoBOL: |
    (ctx, bridge) => bridge.navigation.setPage(
      ctx.bolPage ?? 2
    )
  focusTotal: |
    (ctx, bridge) => bridge.navigation.focusAttribute(
      ctx.dataObjects[0]?.uuid,
      "invoice/total"
    )
  addLineItem: |
    async (ctx, bridge) => {
      const parent = ctx.dataObjects[0];
      const obj = await bridge.data.addDataObject(parent.uuid, "LineItem");
      bridge.navigation.focusAttribute(obj.uuid, "LineItem/Description");
    }
When the reviewer opens this form, four shortcuts appear in the help dialog under “Navigation” and “Data Entry”. Switching to a different form removes them; reopening this form restores them. No manual cleanup is required.

Conformance

The shortcut dispatcher and Bridge API are covered by a conformance suite in kodexa-ui/src/schema/runtime/conformance/. Each binding behaviour ships as a paired .js + .expected.json script that runs against a stub-store-backed Bridge — the suite catches binding regressions before they reach the browser.