Mendix JavaScript Actions Skill

SkillWeb & browsing

Lets your agent create and run JavaScript actions that execute in the browser, using DOM, fetch, or geolocation.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Mendix JavaScript Actions Skill skill

About this capability

Create, call and drop JavaScript actions, client-side logic called from nanoflows, not microflows. Use when behaviour must run in the browser or on the device: DOM, fetch, geolocation, or wrapping a marketplace JS action.

What this skill tells your AI

The instructions your AI receives, as published by mendixlabs/mxcli in .claude/skills/mendix/javascript-actions/SKILL.md and read by ahel’s review.

Guidance for creating, calling, and dropping JavaScript actions in Mendix projects with MDL. JavaScript actions hold custom client-side logic and are called from nanoflows (not microflows — those use Java actions).

When to Use This Skill

  • Adding client-side behaviour (browser/native APIs, DOM, fetch, geolocation, …)
  • Logic that must run on the device rather than the server
  • Calling an existing JavaScript action from a nanoflow
  • Wrapping a marketplace/native capability exposed as a JS action

For server-side custom code, use Java actions instead (see java-actions).

Overview

A JavaScript action is two things on disk:

  1. The model unit (JavaScriptActions$JavaScriptAction).
  2. A source file javascriptsource/<Module>/actions/<Name>.js containing an exported async function.

CREATE JAVASCRIPT ACTION writes both. The MDL body you provide becomes the function body (between the BEGIN USER CODE / END USER CODE markers), so it normally returns a Promise.

Syntax

CREATE [OR MODIFY] JAVASCRIPT ACTION Module.Name ( parameters )
    RETURNS type
    [EXPOSED AS 'caption' IN 'category']
    [PLATFORM Web | Native | Hybrid | All]   -- default Web
AS $$
    <javascript>
$$;

DROP JAVASCRIPT ACTION Module.Name;

Clause order is fixed: returns, then exposed as, then platform, then as.

  • AS $$ ... $$ is mandatory. Omitting the body causes no viable alternative at input '...'. Use a stub: AS $$ return Promise.resolve(false); $$.
  • PLATFORM defaults to Web. Use Native, Hybrid, or All to widen.
  • OR MODIFY updates an existing action in place (UUID preserved); without it, a duplicate name is an error (use create or modify to overwrite).

Parameter types

Same type system as Java actions:

  • Primitives: String, Integer, Long, Decimal, Boolean, DateTime
  • Entity: Module.EntityName · List: List of Module.EntityName
  • Enumeration: ENUM Module.EnumName
  • Type parameter (generics): declare EntityType: ENTITY <pEntity>, then use the bare pEntity for instance parameters
  • Append NOT NULL to mark a parameter required.

Examples

Simple action (Web default):

CREATE JAVASCRIPT ACTION MyFirstModule.JSA_IsOnline () RETURNS Boolean
AS $$
    return Promise.resolve(navigator.onLine);
$$;

Parameters + return:

CREATE JAVASCRIPT ACTION MyFirstModule.JSA_Add (
    A: Integer NOT NULL,
    B: Integer NOT NULL
) RETURNS Integer
AS $$
    return Promise.resolve(A + B);
$$;

Exposed toolbox action, native platform:

CREATE JAVASCRIPT ACTION MyFirstModule.JSA_ShowToast (
    Message: String NOT NULL,
    Duration: Integer
) RETURNS Boolean
EXPOSED AS 'Show Toast' IN 'UI'
PLATFORM Native
AS $$
    console.log(Message);
    return Promise.resolve(true);
$$;

Idempotent update (UUID preserved):

CREATE OR MODIFY JAVASCRIPT ACTION MyFirstModule.JSA_Add (
    A: Integer NOT NULL,
    B: Integer NOT NULL,
    C: Integer
) RETURNS Integer
AS $$
    return Promise.resolve(A + B + (C || 0));
$$;

Drop (removes the unit and the .js file):

DROP JAVASCRIPT ACTION MyFirstModule.JSA_Add;

Calling from a nanoflow

JavaScript actions are invoked with CALL JAVASCRIPT ACTION inside a nanoflow body (arguments use Name = value):

$Sum = call javascript action MyFirstModule.JSA_Add(A = 2, B = 3);

This is the nanoflow counterpart of CALL JAVA ACTION (microflows). Use it in a CREATE NANOFLOW ... BEGIN ... END; body.

The generated .js file

CREATE writes (and OR MODIFY rewrites) javascriptsource/<Module>/actions/<Name>.js:

// This file was generated by Mendix Studio Pro.
// ...
// BEGIN EXTRA CODE
// END EXTRA CODE

/**
 * @param {number} A
 * @param {number} B
 * @returns {Promise.<number>}
 */
export async function JSA_Add(A, B) {
    // BEGIN USER CODE
    return Promise.resolve(A + B);
    // END USER CODE
}

Only the code between the USER CODE / EXTRA CODE markers is preserved when Studio Pro regenerates the file. The MDL $$ body $$ lands inside USER CODE.

Inspecting

SHOW JAVASCRIPT ACTIONS [IN Module];
DESCRIBE JAVASCRIPT ACTION Module.Name;   -- re-executable MDL (signature + body)

DESCRIBE output round-trips: it re-parses as a CREATE JAVASCRIPT ACTION.

Validation Checklist

  • Body present: AS $$ ... $$; — never omit it
  • Body returns a Promise (the function is async)
  • Clause order: returns → exposed as → platform → as
  • Required parameters marked NOT NULL
  • Use CALL JAVASCRIPT ACTION from nanoflows, CALL JAVA ACTION from microflows
  • Validate before applying: mxcli check script.mdl

Common Errors

SymptomCauseFix
no viable alternative at input '...'Missing AS $$ ... $$ bodyAdd a body (stub return Promise.resolve(false);)
already exists — use create or modify to overwriteDuplicate name without OR MODIFYAdd OR MODIFY
Action runs nowhere / wrong clientPLATFORM too narrowSet PLATFORM All (or the right target)
mismatched input 'platform'Clause out of orderPut platform after exposed as, before as

Related Documentation

  • java-actions — server-side custom code (microflows)
  • write-nanoflows — nanoflow syntax and restrictions
  • mxcli syntax javascript-action — quick syntax reference

Signals

GitHub stars
122
Forks
49
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
javascript-actions
Source
github.com/mendixlabs/mxcli