Mendix Fragments Skill
SkillDev toolsLets your agent define reusable widget groups once and place them on multiple pages instead of rebuilding them each time.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Mendix Fragments Skill skill
About this capability
Define reusable widget groups with DEFINE FRAGMENT and place them with USE FRAGMENT. Use when the same widget pattern repeats across pages and should be written once.
What this skill tells your AI
The instructions your AI receives, as published by mendixlabs/mxcli in .claude/skills/mendix/fragments/SKILL.md and read by ahel’s review.
When to Use This Skill
Use this skill when:
- Defining reusable widget groups with
define fragment - Inserting fragments into pages or snippets with
use fragment - Listing or inspecting fragments with
show fragments/describe fragment - Building multiple pages that share common widget patterns (footers, form fields, buttons)
- Avoiding copy-paste of repeated widget structures across pages
What Are Fragments?
Fragments are script-scoped, transient widget groups:
- Defined once, reused in multiple pages/snippets within the same script
- Not persisted in the MPR file — they exist only during script execution
- Widgets are deep-cloned on expansion (each USE gets independent copies)
- Optional prefix support to avoid name conflicts when using the same fragment multiple times
Syntax Reference
DEFINE FRAGMENT
define fragment SaveCancelFooter as {
footer footer1 {
actionbutton btnSave (caption: 'Save', action: save_changes, buttonstyle: primary)
actionbutton btnCancel (caption: 'Cancel', action: cancel_changes)
}
};
Multiple top-level widgets:
define fragment CustomerFields as {
textbox txtName (label: 'Name', attribute: Name)
textbox txtEmail (label: 'Email', attribute: Email)
textbox txtPhone (label: 'Phone', attribute: Phone)
};
USE FRAGMENT
Inside a page or snippet body:
create page Module.CustomerEdit
(
params: { $Customer: Module.Customer },
title: 'Edit Customer',
layout: Atlas_Core.PopupLayout
)
{
dataview dvCustomer (datasource: $Customer) {
use fragment CustomerFields
use fragment SaveCancelFooter
}
};
With prefix (avoids name conflicts):
use fragment SaveCancelFooter as order_
-- Creates: order_footer1, order_btnSave, order_btnCancel
Content Slots — wrap arbitrary content
A plain fragment substitutes a fixed widget group. A content slot lets a
fragment wrap arbitrary caller-supplied content — a reusable shell (a card,
panel, or section) whose body varies per use. Declare a slot where the caller's
widgets should land, then fill it with the use fragment X { … } payload form:
define fragment Card as {
container cardWrap (class: 'card', designproperties: ['Card style': on]) {
container cardBody (class: 'card-body') {
slot content -- caller's widgets are spliced in here
}
}
};
create page Module.Dashboard (title: 'Dashboard', layout: Atlas_Core.Atlas_Default) {
use fragment Card {
dynamictext cardHeading (content: 'Welcome', rendermode: H2)
dynamictext cardText (content: 'Any widgets can go inside the reusable Card shell')
}
};
Rules (v1):
- The slot name is optional and defaults to
content; a fragment supports one slot. - Using a slotted fragment with no payload (
use fragment Card) expands the slot to nothing — a valid empty shell. - Supplying a payload to a fragment that declares no slot is an error.
- The payload is deep-cloned;
as prefix_still renames the fragment's own widgets (not the caller's payload). - The slot resolves at expansion —
describe pageshows the fully-expanded tree (no slot marker), and there are no BSON/round-trip surprises.
For varying a leaf value (a label or attribute name) rather than wrapping a subtree, scalar params (
define fragment F($label, $attr) as …) are a planned v1.1 follow-up; today use a slot plus a one-line value fill.
Parameter bindings — datasource & action (experimental)
The content slot varies structure (which widgets). Typed parameters vary
data and behavior: a fragment can declare a datasource and/or an action
parameter, reference it with $name in a datasource/action position, and receive
its value at the use site. This turns a shell into a real reusable component —
one panel bound to a different entity and a different handler per use.
define fragment DataPanel($data: datasource, $onEdit: action) as {
container panelWrap (class: 'card') {
listview lvItems (datasource: $data) {
slot content
actionbutton btnEdit (caption: 'Edit', action: $onEdit, buttonstyle: primary)
}
}
};
create page Module.Orders (title: 'Orders', layout: Atlas_Core.Atlas_Default) {
use fragment DataPanel ($data: database Module.Order, $onEdit: microflow Module.EditOrder) {
dynamictext panelHeading (content: 'Orders', rendermode: H4)
}
};
Rules:
- Param kinds are
datasource($var/database E/$currentObject/Assoc/microflow M) andaction(a microflow / nanoflow /save_changes/show_page/ …). - Every declared parameter must be supplied; unknown args and type mismatches are errors.
- Values substitute at expansion —
describe pageshows the concrete datasource/action, no$param.
Building blocks can't declare params (they're authored in Studio Pro), but a
use building block accepts rebind overrides that rewrite the block's
outermost datasource and/or its first button after the copy:
use building block Atlas_Web_Content.List_Cards
(datasource: database Module.Order, action: microflow Module.OpenOrder) as orders_;
Binding-point rule (prototype): datasource → the first widget carrying a
datasource; action → the first button widget. For anything more specific, copy
the block in with as prefix_ and use alter page … set … on prefix_widget.
SHOW FRAGMENTS
show fragments;
-- Lists all defined fragments with widget counts
DESCRIBE FRAGMENT
describe fragment SaveCancelFooter;
-- Outputs the full MDL definition
Common Patterns
Pattern 1: Standard CRUD Footer
define fragment CrudFooter as {
footer footer1 {
actionbutton btnSave (caption: 'Save', action: save_changes, buttonstyle: primary)
actionbutton btnCancel (caption: 'Cancel', action: cancel_changes)
}
};
-- Use in every edit page
create page Module.Customer_Edit (...) {
dataview dv (datasource: $Customer) {
textbox txtName (label: 'Name', attribute: Name)
use fragment CrudFooter
}
};
create page Module.Order_Edit (...) {
dataview dv (datasource: $Order) {
textbox txtNumber (label: 'Order #', attribute: Number)
use fragment CrudFooter
}
};
Pattern 2: Form Field Groups
define fragment AddressFields as {
textbox txtStreet (label: 'Street', attribute: Street)
textbox txtCity (label: 'City', attribute: City)
textbox txtZip (label: 'Zip Code', attribute: ZipCode)
textbox txtCountry (label: 'Country', attribute: Country)
};
-- Reuse in customer and supplier pages
create page Module.Customer_Edit (...) {
dataview dv (datasource: $Customer) {
textbox txtName (label: 'Name', attribute: Name)
use fragment AddressFields
use fragment CrudFooter
}
};
Pattern 3: Same Fragment with Prefix
define fragment ActionButtons as {
actionbutton btnApprove (caption: 'Approve', action: save_changes, buttonstyle: success)
actionbutton btnReject (caption: 'Reject', action: cancel_changes, buttonstyle: danger)
};
create page Module.DualPanel (...) {
layoutgrid lg {
row row1 {
column col1 (desktopwidth: 6) {
use fragment ActionButtons as left_
}
column col2 (desktopwidth: 6) {
use fragment ActionButtons as right_
}
}
}
};
Common Mistakes
Duplicate Fragment Names
-- WRONG: Defining the same fragment name twice causes an error
define fragment footer as { ... };
define fragment footer as { ... }; -- Error: fragment "Footer" already defined
Missing Fragment
-- WRONG: Using a fragment that hasn't been defined
create page Module.MyPage (...) {
use fragment NonExistent -- Error: fragment "NonExistent" not found
};
Name Conflicts Without Prefix
-- WRONG: Using same fragment twice without prefix creates duplicate widget names
use fragment footer
use fragment footer -- Widget name "footer1" already exists!
-- CORRECT: Use prefix for uniqueness
use fragment footer as first_
use fragment footer as second_
Fragment Order
-- WRONG: Using a fragment before defining it
create page Module.MyPage (...) {
use fragment footer -- Error: fragment "Footer" not found
};
define fragment footer as { ... };
-- CORRECT: Define before use
define fragment footer as { ... };
create page Module.MyPage (...) {
use fragment footer -- OK
};
Validation Checklist
- All
define fragmentstatements appear before theiruse fragmentreferences - No duplicate fragment names in the script
- Prefix used when the same fragment appears multiple times on one page
- Fragment widget names don't conflict with other widgets on the page
- All widgets inside fragments use valid syntax (same as page bodies)
- A
use fragment X { … }payload is only supplied when fragmentXdeclares aslot - A slotted fragment has exactly one
slot(v1 supports a single slot)
Related Documentation
mxcli syntax fragment— CLI help topiccreate-page— Page/widget syntax referenceoverview-pages— CRUD page patterns- Proposal:
docs/11-proposals/proposal_page_composition.md
Signals
- GitHub stars
- 122
- Forks
- 49
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
fragments- Source
- github.com/mendixlabs/mxcli