Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Widget Types

A widget is declared with a type keyword, a unique name, properties in parentheses, and optional child widgets in braces.

WIDGET_TYPE widgetName (Property: value, ...) [{ children }]

The list below is not the boundary. The built-in Mendix widgets are documented here because they have fixed, hand-written property sets. Every pluggable or custom widget installed in the project is also written by its own name, with a body derived from the widget’s definition — see Any installed widget below. If a widget is in widgets/, MDL can name it.

Widget Categories

CategoryWidgets
LayoutLAYOUTGRID, ROW, COLUMN, CONTAINER, CUSTOMCONTAINER
DataDATAVIEW, LISTVIEW, DATAGRID, GALLERY
InputTEXTBOX, TEXTAREA, CHECKBOX, RADIOBUTTONS, DATEPICKER, COMBOBOX
DisplayDYNAMICTEXT, IMAGE, STATICIMAGE, DYNAMICIMAGE
ActionACTIONBUTTON, LINKBUTTON
NavigationNAVIGATIONLIST
StructureHEADER, FOOTER, CONTROLBAR, SNIPPETCALL

Layout Widgets

LAYOUTGRID

Creates a responsive grid with rows and columns. The primary layout mechanism for arranging widgets on a page:

LAYOUTGRID grid1 {
  ROW {
    COLUMN {
      TEXTBOX txtName (Label: 'Name', Attribute: Name)
    }
    COLUMN {
      TEXTBOX txtEmail (Label: 'Email', Attribute: Email)
    }
  }
  ROW {
    COLUMN {
      TEXTAREA txtNotes (Label: 'Notes', Attribute: Notes)
    }
  }
}

ROW

A row within a LAYOUTGRID. Contains one or more COLUMN children.

COLUMN

A column within a ROW. Contains any number of child widgets. Column width is determined by the layout grid system.

CONTAINER

A generic div container. Used to group widgets and apply CSS classes or styles:

CONTAINER cCard (Class: 'card mx-spacing-top-large') {
  DYNAMICTEXT txtTitle (Content: 'Section Title')
  TEXTBOX txtValue (Label: 'Value', Attribute: Value)
}

Properties:

PropertyDescriptionExample
ClassCSS class namesClass: 'card p-3'
StyleInline CSS stylesStyle: 'padding: 16px;'
DynamicClassesRuntime-computed CSS classes (expression; stacks on Class)DynamicClasses: if $currentObject/IsActive then 'is-active' else ''
DesignPropertiesDesign property valuesDesignProperties: ('Spacing top': 'Large')

CUSTOMCONTAINER

Similar to CONTAINER but used for custom-styled containers.

Data Widgets

DATAVIEW

Displays a single object. The central widget for detail and edit pages. Must have a data source:

DATAVIEW dvCustomer (DataSource: $Customer) {
  TEXTBOX txtName (Label: 'Name', Attribute: Name)
  TEXTBOX txtEmail (Label: 'Email', Attribute: Email)
  COMBOBOX cbStatus (Label: 'Status', Attribute: Status)
  FOOTER {
    ACTIONBUTTON btnSave (Caption: 'Save', Action: SAVE CHANGES, ButtonStyle: Primary)
    ACTIONBUTTON btnCancel (Caption: 'Cancel', Action: CANCEL CHANGES)
  }
}

Data source options:

  • DataSource: $ParamName – page parameter
  • DataSource: MICROFLOW Module.MF_Name – microflow returning a single object
  • DataSource: NANOFLOW Module.NF_Name – nanoflow returning a single object
  • DataSource: SELECTION widgetName – currently selected item from a list widget
  • DataSource: ASSOCIATION AssocName – follow an association from a parent context

DATAGRID

Displays a list of objects in a tabular format with columns, sorting, and pagination:

DATAGRID dgOrders (DataSource: DATABASE Sales.Order, PageSize: 20) {
  COLUMN (Attribute: OrderId, Caption: 'Order #')
  COLUMN (Attribute: OrderDate, Caption: 'Date')
  COLUMN (Attribute: Amount, Caption: 'Amount', Alignment: right)
  COLUMN (Attribute: Status, Caption: 'Status')
  CONTROLBAR {
    ACTIONBUTTON btnNew (Caption: 'New', Action: CALL MICROFLOW Sales.ACT_CreateOrder, ButtonStyle: Primary)
  }
}

DataGrid properties:

PropertyDescriptionExample
DataSourceData source (DATABASE, MICROFLOW, etc.)DataSource: DATABASE Module.Entity
PageSizeNumber of rows per pagePageSize: 25
PaginationPagination modePagination: virtualScrolling
PagingPositionPosition of paging controlsPagingPosition: both
ShowPagingButtonsWhen to show paging buttonsShowPagingButtons: auto

Column properties:

PropertyValuesDefaultDescription
Attributeattribute name, or association path Assoc/Attr(required)The attribute to display. Use an association path to show an attribute over a reference — e.g. Attribute: Order_Customer/Name shows the associated Customer’s Name. Association names are bare (resolved against the grid’s entity module); multi-hop paths (A/B/Attr) are supported.
Captionstringattribute nameColumn header text
Alignmentleft, center, rightleftText alignment
WrapTexttrue, falsefalseAllow text wrapping
Sortabletrue, falsevariesAllow sorting by this column
Resizabletrue, falsetrueAllow column resizing
Draggabletrue, falsetrueAllow column reordering
Hidableyes, hidden, noyesUser visibility toggle
ColumnWidthautoFill, autoFit, manualautoFillWidth mode
Sizeinteger (px)1Width in pixels (manual mode)
Visibleexpression stringtrueVisibility expression
DynamicCellClassexpression string(empty)Dynamic CSS class expression
Tooltiptext string(empty)Column tooltip

LISTVIEW

Displays a list of objects using a repeating template. More flexible than DataGrid for custom layouts:

LISTVIEW lvProducts (DataSource: DATABASE MyModule.Product) {
  CONTAINER cItem (Class: 'list-item') {
    DYNAMICTEXT txtName (Content: '{1}', Attribute: Name)
    DYNAMICTEXT txtPrice (Content: '${1}', Attribute: Price)
  }
}

Database source over an association

Inside a data container, a list view can retrieve from the database the objects an association of the context object points to. Studio Pro calls it a Database source with an entity path; it keeps an XPath constraint, a sort order and a search bar:

create snippet MyModule.TaskAssignees (Params: ($Task: System.WorkflowUserTask)) {
  listview lvAssignees (
    DataSource: database from $Task/System.WorkflowUserTask_Assignees/Administration.Account
      where [Active = true()] sort by FullName asc search by FullName
  ) {
    dynamictext txtName (Content: '{1}', ContentParams: ({1} = FullName))
  }
};

The path pairs each association with the entity it arrives at. Name the entity: it may be a specialization of the association’s own end (here Administration.Account for System.User), and DESCRIBE always prints it. A trailing association with no entity gets the end opposite the context.

It is a different source from $Task/System.WorkflowUserTask_Assignees — an association source, which follows the association in memory and has no XPath, sort or search. List views only; on any other widget it is refused.

Specialization templates

When the list view’s entity is a generalization, it can render a different body per specialization. A template is identified by the entity it renders — it has no name, hence TEMPLATE FOR <entity>:

LISTVIEW vehicleListView (DataSource: DATABASE Pages.Vehicle) {
  -- the default body, used for an object no template matches
  DYNAMICTEXT defaultVehicle (Content: '{1} {2}', ContentParams: ({1} = Brand, {2} = Model))

  TEMPLATE FOR Pages.Bus {
    DYNAMICTEXT busLabel (Content: 'Bus, capacity {1}', ContentParams: ({1} = PassengerCapacity))
  }
  TEMPLATE FOR Pages.Truck {
    DYNAMICTEXT truckLabel (Content: 'Truck, max load {1} kg', ContentParams: ({1} = MaxLoadKg))
  }
}

Widgets written directly in the list view body are the default rendering. Templates keep their source order: Mendix stores and matches in that order, so it is authored rather than derived, and DESCRIBE PAGE emits them as stored.

Inside a template the context object is the specialization, so an attribute only that specialization has still resolves — PassengerCapacity above exists on Pages.Bus, not on Pages.Vehicle.

The entity must be the list view’s entity or a specialization of it, and there may be at most one template per entity; both are refused rather than written, because a template that cannot match never renders.

A Gallery’s TEMPLATE <name> is a different construct — a named content slot, not a per-specialization body.

A pluggable widget that displays items in a card/grid layout:

GALLERY galProducts (DataSource: DATABASE MyModule.Product) {
  CONTAINER cCard {
    DYNAMICTEXT txtName (Content: '{1}', Attribute: Name)
  }
}

Responsive column properties control how many columns the grid uses per breakpoint:

PropertyDescriptionDefault
DesktopColumnsNumber of columns on desktop1
TabletColumnsNumber of columns on tablet1
PhoneColumnsNumber of columns on phone1
GALLERY galBoard (
  DataSource: DATABASE MyModule.Cell,
  DesktopColumns: 9,
  TabletColumns: 4,
  PhoneColumns: 2
) {
  DYNAMICTEXT txtVal (Content: '{1}', Attribute: Value)
}

Input Widgets

All input widgets share common properties:

PropertyDescriptionExample
LabelField label textLabel: 'Customer Name'
AttributeEntity attribute to bind toAttribute: Name
EditableEditability modeEditable: ReadOnly
VisibleVisibility expressionVisible: '$showField'

Each input widget takes only some attribute types. Measured with mxbuild 11.14.0, every other pairing is CE2421 (“Only attributes of type … are allowed here.”):

WidgetAttribute types
TEXTBOXString, Integer, Long, Decimal, AutoNumber (and Hashed string)
TEXTAREAString
DATEPICKERDateTime
CHECKBOXBoolean
RADIOBUTTONSBoolean, Enumeration
DROPDOWNEnumeration

With -p, check --references reports a mismatch as MDL-WIDGET39, judging the attribute at the end of an association path and on the generalization that declares it. It also reports a bare association bound where an attribute belongs (Attribute: Order_Customer), which mxbuild answers with CE1613 and which stops mx check from reporting anything else. An enumeration takes RADIOBUTTONS or COMBOBOX.

The classic drop-down (DROPDOWN, stored as Forms$DropDown) is not supported by the React client: on a project whose Web UI setting is OptimizedClient: Yes (show settings), mxbuild reports CE0582 and check --references reports MDL-WIDGET40. Use COMBOBOX over the same attribute. Under No and MigrationMode the drop-down builds, and nothing is reported.

TEXTBOX

Single-line text input. The most common input widget:

TEXTBOX txtName (Label: 'Name', Attribute: Name)
TEXTBOX txtEmail (Label: 'Email', Attribute: Email)

TEXTAREA

Multi-line text input for longer text:

TEXTAREA txtDescription (Label: 'Description', Attribute: Description)

CHECKBOX

Boolean (true/false) input:

CHECKBOX cbActive (Label: 'Active', Attribute: IsActive)

RADIOBUTTONS

Displays enumeration or boolean values as radio buttons:

RADIOBUTTONS rbStatus (Label: 'Status', Attribute: Status)

DATEPICKER

Date and/or time input:

DATEPICKER dpBirthDate (Label: 'Birth Date', Attribute: BirthDate)

COMBOBOX

Dropdown selection for enumeration values or associations. Uses the pluggable ComboBox widget:

COMBOBOX cbStatus (Label: 'Status', Attribute: Status)

REFERENCESELECTOR

The classic reference selector (Forms$ReferenceSelector) is a built-in Forms widget mxcli has no writer for. The keyword parses, and check refuses it as MDL-WIDGET38 rather than letting exec stop at the page. Select an associated object with a COMBOBOX over the association instead; it needs its own datasource: (CE0642 without one) and a caption attribute.

Display Widgets

DYNAMICTEXT

Displays dynamic text content, often with attribute values:

DYNAMICTEXT txtGreeting (Content: 'Welcome, {1}', Attribute: Name)

IMAGE / STATICIMAGE / DYNAMICIMAGE

Display images on a page:

-- Static image from the project
STATICIMAGE imgLogo (Image: 'MyModule.Logo')

-- Dynamic image from an entity attribute (entity must extend System.Image)
DYNAMICIMAGE imgPhoto (DataSource: $Photo, Width: 200, Height: 150)

-- Generic image widget
IMAGE imgBanner (Width: 800, Height: 200)

Image properties:

PropertyDescriptionExample
WidthWidth in pixelsWidth: 200
HeightHeight in pixelsHeight: 150

Action Widgets

ACTIONBUTTON

A button that triggers an action. The primary interactive element:

ACTIONBUTTON btnSave (Caption: 'Save', Action: SAVE CHANGES, ButtonStyle: Primary)
ACTIONBUTTON btnCancel (Caption: 'Cancel', Action: CANCEL CHANGES)
ACTIONBUTTON btnDelete (Caption: 'Delete', Action: DELETE, ButtonStyle: Danger)

Action types:

ActionDescription
SAVE CHANGESCommit and close the page
CANCEL CHANGESRoll back and close the page
DELETEDelete the current object
CLOSE PAGEClose the page without saving
CALL MICROFLOW Module.MF_NameCall a microflow
CALL NANOFLOW Module.NF_NameCall a nanoflow
SHOW PAGE Module.PageNameOpen a page
CREATE OBJECT Module.Entity THEN SHOW PAGE Module.PageNameCreate an object and open a page for it
OPEN LINK 'https://…'Open a web address
SIGN OUTSign the user out
COMPLETE TASK 'Outcome'Complete a workflow user task

The snake-case spellings (SAVE_CHANGES, SHOW_PAGE, …) and MICROFLOW … without CALL are deprecated aliases (MDL-DEPR020).

Button styles:

StyleTypical appearance
DefaultStandard button
PrimaryBlue/highlighted button
SuccessGreen button
WarningYellow/amber button
DangerRed button
InfoLight blue button

Microflow action with parameters:

ACTIONBUTTON btnProcess (
  Caption: 'Process',
  Action: CALL MICROFLOW Sales.ACT_ProcessOrder(Order = $Order),
  ButtonStyle: Primary
)

Icon — Icon: 'Module.IconCollection.IconName' gives the button an icon from an icon collection (the modern Atlas icon set). The name must exist in the collection, or MxBuild rejects it (CE1613):

ACTIONBUTTON btnEdit (Caption: 'Edit', Action: PAGE App.Edit,
  Icon: 'Atlas_Core.Atlas_Filled.pencil')

LINKBUTTON

Renders as a hyperlink instead of a button. Same action types, styles, and Icon: as ACTIONBUTTON:

LINKBUTTON lnkDetails (Caption: 'View Details', Action: PAGE MyModule.Customer_Detail)
LINKBUTTON lnkEdit (Caption: 'Edit', Action: PAGE App.Edit, Icon: 'Atlas_Core.Atlas_Filled.pencil')

Structure Widgets

Header section of a DataView, placed before the main content:

DATAVIEW dvOrder (DataSource: $Order) {
  HEADER hdr1 {
    DYNAMICTEXT txtOrderTitle (Content: 'Order #{1}', Attribute: OrderId)
  }
  TEXTBOX txtStatus (Label: 'Status', Attribute: Status)
  FOOTER { ... }
}

Footer section of a DataView. Typically contains save/cancel buttons. It stores no name of its own; ALTER PAGE addresses it as <dataview>.footer:

FOOTER {
  ACTIONBUTTON btnSave (Caption: 'Save', Action: SAVE CHANGES, ButtonStyle: Primary)
  ACTIONBUTTON btnCancel (Caption: 'Cancel', Action: CANCEL CHANGES)
}

CONTROLBAR

Control bar for DataGrid widgets. Contains action buttons for the grid:

CONTROLBAR bar1 {
  ACTIONBUTTON btnNew (Caption: 'New', Action: CALL MICROFLOW Module.ACT_Create, ButtonStyle: Primary)
  ACTIONBUTTON btnEdit (Caption: 'Edit', Action: PAGE Module.Entity_Edit)
  ACTIONBUTTON btnDelete (Caption: 'Delete', Action: DELETE, ButtonStyle: Danger)
}

SNIPPETCALL

Embeds a snippet (reusable page fragment) into the page:

SNIPPETCALL scNav (Snippet: MyModule.NavigationMenu)

Renders a navigation list with clickable items:

NAVIGATIONLIST navMain {
  -- navigation items
}

Any installed widget

Everything above is a built-in widget: its keyword and properties are fixed by Mendix and by mxcli. A pluggable or custom widget — DataGrid 2, Combo box, Gallery, HTML Element, the charts, anything from the Marketplace, anything your team built — is named the same way, by its own MDL name:

htmlelement frame (tagName: 'div', tagContentMode: 'container') {
  attribute a1 (attributeName: 'data-testid', attributeValueType: 'expression')
  tagcontentcontainer body {
    dynamictext caption (Content: 'Inside the element')
  }
}

Three things there come from the widget’s own definition rather than from any list in mxcli:

  • The keyword htmlelement — the widget’s MDL name, which is the last segment of its widget id.
  • The properties tagName, tagContentMode — written with the widget’s own spelling, exactly as DESCRIBE WIDGET reports them.
  • The body containers attribute (an object list, one entry per repetition) and tagcontentcontainer (a child slot, holding widgets).

A property whose type in the widget’s definition is Expression — an HTML element attribute’s attributeValueExpression, a chart series’ dynamicBarColor — takes a Mendix expression written as-is:

attribute a1 (attributeName: 'data-hot', attributeValueType: 'expression',
              attributeValueExpression: if $currentObject/Hot then 'hot' else 'cold')

The same unquoted expression on a property of any other type (a text template, a plain value) is refused by check as MDL-WIDGET42 rather than written empty.

Finding the names

Ask the widget:

DESCRIBE WIDGET TYPE htmlelement;

It lists every property with its type, default and enumeration members, every body container and whether MDL can express it, and a complete example that parses and checks as written. See DESCRIBE WIDGET.

The explicit form

A widget can also be named by its full id. This is the fallback, not the norm — use it when two installed packages ship the same MDL name, or when you have the id in hand and not the name:

pluggablewidget 'com.mendix.widget.web.htmlelement.HTMLElement' frame (
  tagName: 'div'
)

DESCRIBE PAGE emits the short form wherever it round-trips, and falls back to the id form when the name would be ambiguous.

When a widget is not found

A name that resolves to no installed definition is an error, not a silently accepted widget — MDL-WIDGET25, with the nearest known names suggested. A container keyword the parent widget does not declare is MDL-WIDGET26. Both need a project open (-p), since without one mxcli knows only its embedded widgets.

A third, MDL-WIDGET29, needs no project: statictext writes Forms$Text, and Mendix has no such type. That is not a build error but a load error — mx check and Studio Pro both stop at TypeCacheUnknownTypeException before any validation runs, so the page cannot even be opened to repair it. Use DYNAMICTEXT with a literal Content:.

If a widget you have installed is not found, its definition has not been extracted yet:

mxcli widget init -p app.mpr     # extract definitions for every widget in widgets/

Binding a text-template property

Many pluggable widgets expose text-template properties — an Image’s ImageUrl and AlternativeText, a TreeNode’s headerCaption, a Timeline’s title / description / timeIndication. They take text, so a bare value is stored as a literal and renders the same string on every row, with check, exec and mx check all clean.

Bind one with the property’s own <Name>Params companion:

image cardImage (
  ImageType: imageUrl,
  ImageUrl: '{1}',        ImageUrlParams: ({1} = PictureUrl),
  AlternativeText: '{1}', AlternativeTextParams: ({1} = Name)
)

The companion is the property’s own name + Params, in whichever spelling the template itself was written. It takes the same per-parameter format (...) block a dynamictext does, and DESCRIBE PAGE emits both the template and its companion — for the Image and for every other pluggable widget — so describe → exec keeps the binding. Before ako/mxcli#575 the generic describe path read attribute references and primitives only, so a TreeNode’s headerCaption and a Timeline’s title were missing from its output altogether.

Two shorter spellings remain:

SpellingUse it for
'{AttrName}'one attribute, no formatting block
contentparams: (...)a widget with a single text template — it is one list shared by every template on the widget

Every {N} needs a matching parameter (Mendix rejects a shortfall with CE0720), and parameters with no {N} to fill are reported as MDL-WIDGET21 rather than dropped in silence.

Common Widget Properties

These properties are shared across many widget types:

PropertyDescriptionExample
ClassCSS class namesClass: 'card p-3'
StyleInline CSS stylesStyle: 'margin-top: 8px;'
DynamicClassesRuntime-computed CSS classes (expression; stacks on Class)DynamicClasses: if $currentObject/IsActive then 'is-active' else ''
DesignPropertiesAtlas design propertiesDesignProperties: ('Spacing top': 'Large', 'Full width': ON)
VisibleVisibility expressionVisible: '$showSection'
EditableEditability modeEditable: ReadOnly

See Also