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.
- Static type safety β Gleam's robust type system catches runtime errors at compile time
- Immutable data β Predictable state management
- JavaScript target support β
gleam build --target javascriptoutputs ES modules - glendix + mendraw packages β Type-safe Gleam bindings for React + Mendix API + JS Interop, supporting
EditableValue,ActionValue,ListValueand all other Mendix Pluggable Widget API types
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.5 + 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.
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/
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)
// ...
}- Gleam (v1.0+)
- Node.js (v16+)
- Mendix Studio Pro (for widget testing)
gleam run -m glendix/install # Auto-downloads Gleam deps + installs npm deps + generates binding code (external React packages must be installed manually beforehand)gleam run -m glendix/build # Gleam compilation + widget build (.mpk output)Build artefacts are output as .mpk files in the dist/ directory.
gleam run -m glendix/dev # Gleam compilation + dev server (HMR, port 3000)
gleam run -m glendix/start # Linked development with Mendix test projectAll commands are unified under gleam. gleam run -m automatically compiles Gleam before running the script.
| Command | Description |
|---|---|
gleam run -m glendix/install |
Install dependencies (Gleam + npm) + generate binding code |
gleam run -m glendix/build |
Production build (.mpk output) |
gleam run -m glendix/dev |
Development server (HMR, port 3000) |
gleam run -m glendix/start |
Linked development with Mendix test project |
gleam run -m glendix/lint |
Run ESLint |
gleam run -m glendix/lint_fix |
ESLint auto-fix |
gleam run -m glendix/release |
Release build |
gleam run -m mendraw/marketplace |
Search/download Mendix Marketplace widgets |
gleam run -m glendix/define |
Widget property definition TUI editor |
gleam build --target javascript |
Gleam to JS compilation only |
gleam test |
Run Gleam tests |
gleam format |
Format Gleam code |
React component libraries distributed as npm packages can be used from pure Gleam without writing any .mjs FFI files.
npm install rechartsAdd a [tools.glendix.bindings] section to your gleam.toml:
[tools.glendix.bindings.recharts]
components = ["PieChart", "Pie", "Cell", "Tooltip", "ResponsiveContainer"]gleam run -m glendix/installA binding_ffi.mjs file is generated automatically. It is also regenerated on subsequent builds via gleam run -m glendix/build.
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.
- Gleam β Widget logic and UI (compiled to JavaScript target)
- glendix β Build tools + JS Interop Gleam bindings (Hex package)
- mendraw β Mendix API Gleam bindings (Hex package)
- React 19 β Mendix Pluggable Widget runtime
- Rollup β Bundling via
@mendix/pluggable-widgets-tools
- The Gleam to JS to Mendix Widget pipeline is not an officially supported combination; build configuration customisation may be required
- JSX files are not used β all React logic is implemented via Gleam + glendix
- React bindings use redraw/redraw_dom via glendix β other Gleam React libraries are not used
- FFI files are not written directly in the widget project β React/Mendix FFI is provided by glendix
Apache License 2.0 β see LICENSE