Live CortexUI Surface

This block renders live CortexUI contract metadata in the docs DOM so AI View can inspect real machine-readable elements instead of only code examples.

AI View can now inspect a live status region, form fields, actions, and table entities on every docs page.
AI-addressable docs entities
ItemState
Search docsReady
Inspect metadataVisible in AI View

Events Reference

Events are the observable outcomes of user and agent interactions. Every significant operation in a CortexUI application emits a structured event that the runtime records and agents can query. Events close the feedback loop — they are how an agent knows whether what it did actually worked.

The 5 Event Types

Event TypeFired WhenKey Payload Fields
action_triggeredAn action element is activatedactionId, action, section
action_completedAn action resolved successfullyactionId, action, result
action_failedAn action rejected or erroredactionId, action, error
form_submittedA form's submit action firedformId, fields
field_updatedA field's value changedfieldId, fieldType, value

Event Payload Structure

All events share a common envelope, with type-specific payload fields.

action_triggered

Emitted the moment an action is activated — before any async operation begins.

{
  "type": "action_triggered",
  "timestamp": "2026-03-30T14:22:05.412Z",
  "payload": {
    "actionId": "save-profile",
    "action": "save-profile",
    "section": "profile-form",
    "screen": "user-profile"
  }
}

action_completed

Emitted when an action's async operation resolves successfully.

{
  "type": "action_completed",
  "timestamp": "2026-03-30T14:22:06.891Z",
  "payload": {
    "actionId": "save-profile",
    "action": "save-profile",
    "result": "success",
    "durationMs": 1479,
    "screen": "user-profile"
  }
}

action_failed

Emitted when an action's async operation rejects or returns an error.

{
  "type": "action_failed",
  "timestamp": "2026-03-30T14:22:06.103Z",
  "payload": {
    "actionId": "submit-order",
    "action": "submit-order",
    "error": "payment-declined",
    "durationMs": 691,
    "screen": "checkout"
  }
}

form_submitted

Emitted when a form's submit action fires, carrying a snapshot of the field values at submission time.

{
  "type": "form_submitted",
  "timestamp": "2026-03-30T14:22:05.420Z",
  "payload": {
    "formId": "edit-profile-form",
    "screen": "user-profile",
    "fields": [
      { "fieldId": "name-field", "fieldType": "text", "value": "Alice Smith" },
      { "fieldId": "email-field", "fieldType": "email", "value": "alice@example.com" },
      { "fieldId": "phone-field", "fieldType": "tel", "value": "+1-555-0100" }
    ]
  }
}

field_updated

Emitted when a field's value changes — on blur or on change, depending on configuration.

{
  "type": "field_updated",
  "timestamp": "2026-03-30T14:22:04.889Z",
  "payload": {
    "fieldId": "email-field",
    "fieldType": "email",
    "value": "alice@example.com",
    "formId": "edit-profile-form",
    "screen": "user-profile"
  }
}
Note

field_updated events for password fields never include the value in the payload. The value is redacted and replaced with the string "[redacted]" to prevent credentials from appearing in event logs.

How Events Are Emitted

Events are emitted by CortexUI components automatically when the corresponding interactions occur. You do not need to write event emission code manually when using the design system's built-in components.

For custom components, emit events using the CortexUI runtime:

import { emitCortexEvent } from "@cortexui/runtime";

// Emit action_triggered
emitCortexEvent({
  type: "action_triggered",
  payload: {
    actionId: "save-profile",
    action: "save-profile",
    section: "profile-form",
    screen: "user-profile"
  }
});

// After the async operation resolves
emitCortexEvent({
  type: "action_completed",
  payload: {
    actionId: "save-profile",
    action: "save-profile",
    result: "success",
    durationMs: performance.now() - startTime,
    screen: "user-profile"
  }
});

How to Listen to Events

You can subscribe to the CortexUI event stream using the onCortexEvent listener:

import { onCortexEvent } from "@cortexui/runtime";

// Listen to all events
const unsubscribe = onCortexEvent((event) => {
  console.log(event.type, event.payload);
});

// Later, clean up
unsubscribe();

// Listen to specific event types
const unsubscribe = onCortexEvent((event) => {
  if (event.type === "action_completed") {
    analytics.track("action_completed", event.payload);
  }
  if (event.type === "action_failed") {
    errorReporting.capture(event.payload.error, {
      actionId: event.payload.actionId
    });
  }
});

You can also listen to raw DOM events dispatched on window:

window.addEventListener("cortexui:event", (e: CustomEvent) => {
  const { type, payload } = e.detail;
  // handle event
});

How getRecentEvents() Returns Events

The CortexUI runtime keeps a rolling buffer of the last 50 events. AI agents query this buffer synchronously using getRecentEvents().

const events = window.__CORTEX_UI__.getRecentEvents();

/*
[
  {
    "type": "action_triggered",
    "timestamp": "2026-03-30T14:22:05.412Z",
    "payload": { "actionId": "save-profile", "action": "save-profile", ... }
  },
  {
    "type": "form_submitted",
    "timestamp": "2026-03-30T14:22:05.420Z",
    "payload": { "formId": "edit-profile-form", "fields": [...] }
  },
  {
    "type": "action_completed",
    "timestamp": "2026-03-30T14:22:06.891Z",
    "payload": { "actionId": "save-profile", "result": "success", ... }
  }
]
*/

Events are returned in chronological order, oldest first. The buffer resets on page navigation.

Example: Agent Flow Using Events to Verify Success

Here is a complete example of an AI agent using events to verify that a profile save succeeded before proceeding:

async function saveUserProfile(userId: string, data: ProfileData) {
  const runtime = window.__CORTEX_UI__;

  // 1. Verify we're on the right screen
  const ctx = runtime.getScreenContext();
  if (ctx.screen !== "user-profile" || ctx.entityId !== userId) {
    throw new Error(`Wrong screen: expected user-profile/${userId}, got ${ctx.screen}/${ctx.entityId}`);
  }

  // 2. Check the action is available
  const actions = runtime.getAvailableActions();
  const saveAction = actions.find(a => a.action === "save-profile");

  if (!saveAction) {
    throw new Error("save-profile action not available on this screen");
  }
  if (saveAction.state !== "idle") {
    throw new Error(`save-profile is not idle: ${saveAction.state}`);
  }

  // 3. Fill the form
  const schema = runtime.getFormSchema("edit-profile-form");
  for (const field of schema.fields) {
    if (data[field.fieldId] !== undefined) {
      const el = document.querySelector(`[data-ai-id="${field.fieldId}"]`);
      if (el) {
        (el as HTMLInputElement).value = data[field.fieldId];
        el.dispatchEvent(new Event("input", { bubbles: true }));
        el.dispatchEvent(new Event("blur", { bubbles: true }));
      }
    }
  }

  // 4. Trigger the action
  const saveButton = document.querySelector('[data-ai-id="save-profile"]');
  saveButton?.dispatchEvent(new MouseEvent("click", { bubbles: true }));

  // 5. Wait for the outcome event
  const outcome = await waitForEvent(
    (event) =>
      (event.type === "action_completed" || event.type === "action_failed") &&
      event.payload.actionId === "save-profile",
    { timeoutMs: 10000 }
  );

  if (outcome.type === "action_failed") {
    throw new Error(`Save failed: ${outcome.payload.error}`);
  }

  // 6. Confirm via state attribute
  const button = document.querySelector('[data-ai-id="save-profile"]');
  const finalState = button?.getAttribute("data-ai-state");
  if (finalState !== "success") {
    throw new Error(`Unexpected final state: ${finalState}`);
  }

  return { success: true, result: outcome.payload.result };
}
Best Practice

Always verify success using both the event stream (action_completed) and the element's data-ai-state attribute. Events confirm the operation resolved; the state attribute confirms the UI reflected that resolution. If they disagree, a state synchronization bug exists in the component.

Event Retention and Privacy

The rolling event buffer is in-memory and cleared on navigation. It is never persisted to localStorage or sent to external services by the CortexUI runtime itself — that is the application's responsibility if desired.

Field values in field_updated and form_submitted events are included by default. If your application handles sensitive data (e.g., SSNs, credit card numbers), mark those fields:

<input
  data-ai-role="field"
  data-ai-id="ssn-field"
  data-ai-field-type="text"
  data-ai-required="true"
  data-ai-sensitive="true"
  type="password"
  name="ssn"
/>

The data-ai-sensitive="true" attribute causes the runtime to redact the value in all event payloads.