MendixWidgetGleam

English | 한국어 | 日本語

Build Mendix Pluggable Widgets with Gleam — no JSX required.

Write React components entirely in Gleam and run them as Mendix Studio Pro widgets. React bindings are provided by redraw/redraw_dom, Mendix API bindings by mendraw, and build tools + JS interop by glendix.

Why Gleam?

Architecture

src/
  mendix_widget_gleam.gleam           # Main widget module
  editor_config.gleam                 # Studio Pro property panel configuration
  editor_preview.gleam                # Studio Pro design view preview
  components/
    hello_world.gleam               # Shared Hello World component
  MendixWidget.xml                    # Widget property definitions
  package.xml                         # Mendix package manifest
package.json                            # npm dependencies (React, external libraries, etc.)
gleam.toml                            # Includes glendix >= 4.0.4 + mendraw dependency

React/Mendix FFI and JS Interop bindings are not included in this project — they are provided by the glendix and mendraw Hex packages.

Build Pipeline

Widget code (.gleam) + glendix package (Hex)
    |  gleam run -m glendix/build (Gleam compilation runs automatically)
ES modules (.mjs) — build/dev/javascript/...
    |  Bridge JS (auto-generated) handles imports
    |  Rollup (pluggable-widgets-tools)
.mpk widget package — dist/

Core Principles

The Gleam function fn(JsProps) -> Element has an identical signature to a React functional component. React bindings are provided by redraw / redraw_dom, while mendraw provides Mendix runtime type accessors and glendix provides JS interop, so widget projects need only focus on business logic.

// src/mendix_widget_gleam.gleam
import mendraw/mendix.{type JsProps}
import redraw.{type Element}
import redraw/dom/attribute
import redraw/dom/html

pub fn widget(props: JsProps) -> Element {
  let sample_text = mendix.get_string_prop(props, "sampleText")
  html.div([attribute.class("widget-hello-world")], [
    html.text("Hello " <> sample_text),
  ])
}

Mendix complex types can also be used in a type-safe manner from Gleam:

import mendraw/mendix
import mendraw/mendix/editable_value
import mendraw/mendix/action

pub fn widget(props: JsProps) -> Element {
  // Access EditableValue
  let name_attr: EditableValue = mendix.get_prop_required(props, "name")
  let display = editable_value.display_value(name_attr)

  // Execute ActionValue
  let on_save: Option(ActionValue) = mendix.get_prop(props, "onSave")
  action.execute_action(on_save)
  // ...
}

Getting Started

Prerequisites

Installation

gleam run -m glendix/install   # Auto-downloads Gleam deps + installs npm deps + generates binding code (external React packages must be installed manually beforehand)

Build

gleam run -m glendix/build     # Gleam compilation + widget build (.mpk output)

Build artefacts are output as .mpk files in the dist/ directory.

Development

gleam run -m glendix/dev       # Gleam compilation + dev server (HMR, port 3000)
gleam run -m glendix/start     # Linked development with Mendix test project

Commands

All commands are unified under gleam. gleam run -m automatically compiles Gleam before running the script.

CommandDescription
gleam run -m glendix/installInstall dependencies (Gleam + npm) + generate binding code
gleam run -m glendix/buildProduction build (.mpk output)
gleam run -m glendix/devDevelopment server (HMR, port 3000)
gleam run -m glendix/startLinked development with Mendix test project
gleam run -m glendix/lintRun ESLint
gleam run -m glendix/lint_fixESLint auto-fix
gleam run -m glendix/releaseRelease build
gleam run -m mendraw/marketplaceSearch/download Mendix Marketplace widgets
gleam run -m glendix/defineWidget property definition TUI editor
gleam build --target javascriptGleam to JS compilation only
gleam testRun Gleam tests
gleam formatFormat Gleam code

Using External React Components

React component libraries distributed as npm packages can be used from pure Gleam without writing any .mjs FFI files.

Step 1: Install the npm package

npm install recharts

Step 2: Add bindings to gleam.toml

Add a [tools.glendix.bindings] section to your gleam.toml:

[tools.glendix.bindings.recharts]
components = ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]

Step 3: Generate bindings

gleam run -m glendix/install

A binding_ffi.mjs file is generated automatically. It is also regenerated on subsequent builds via gleam run -m glendix/build.

Step 4: Use from Gleam

import glendix/binding
import mendraw/interop
import redraw.{type Element}
import redraw/dom/attribute.{type Attribute}

fn m() { binding.module("recharts") }

pub fn pie_chart(attrs: List(Attribute), children: List(Element)) -> Element {
  interop.component_el(binding.resolve(m(), "PieChart"), attrs, children)
}

pub fn tooltip(attrs: List(Attribute)) -> Element {
  interop.void_component_el(binding.resolve(m(), "Tooltip"), attrs)
}

External React components follow the same calling pattern as html.div.

Tech Stack

Limitations

Licence

Apache License 2.0 — see LICENSE

Search Document