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

CREATE PAGE

Synopsis

CREATE [ OR REPLACE ] PAGE module.Name [ FOLDER 'path' ]
(
    [ Params: ( $param : Module.Entity | Type [optional] [, ...] ), ]
    Title: 'title',
    Layout: Module.LayoutName
    [, Variables: ( $name : type = <expression> [, ...] ) ]
)
{
    widget_tree
}

Description

Creates a new page in the specified module. A page defines a user interface screen with a title, a layout, optional parameters, and a hierarchical widget tree.

If OR REPLACE is specified and a page with the same qualified name already exists, it is replaced. Otherwise, creating a page with an existing name is an error.

A replace (OR REPLACE or OR MODIFY) is refused when the stored page holds a widget MDL cannot author — a classic data grid, a reference selector, a drop-down, a reference set selector — that the statement does not declare by name, because the rebuilt page would not contain it. DESCRIBE PAGE marks each such widget with a -- NOT re-executable comment, and the error lists them. Change the page with ALTER PAGE, which keeps them, or remove them on purpose first (ALTER PAGE M.P { DROP grid1; };). The same applies to snippets and layouts, and mxcli check -p reports it before anything is written.

Page Properties

The page declaration block ( ... ) contains comma-separated key-value properties:

  • Params – Page parameters. Each parameter has a $-prefixed name and a type — either an entity (Module.Entity) or a primitive (String, Integer, Decimal, Boolean, DateTime). Parameters are passed when the page is opened (e.g., from a microflow SHOW PAGE or from a data view). Primitive parameters require Mendix 11.6+. A parameter is required unless it says optional ($Sale: Shop.Sale optional, Studio Pro’s unticked Required, Mendix 11.5+): an optional parameter lets the page be opened with no argument, from a menu item for example, where a required one is CE1571. describe page prints it, and a snippet parameter cannot be optional. A parameter cannot be named with a platform-reserved word — Context, Type, Id, Owner, Object, CurrentUser or a Java keyword, in any case and even quoted: Mendix reports CE7247 “The name ‘Context’ is a reserved word.”, and mxcli check refuses it (MDL-PARAM01). The same holds for snippet, Java action and JavaScript action parameters.
  • Title – The page title displayed in the browser tab or page header.
  • Layout – The layout the page is based on. Must be a qualified name referring to an existing layout (e.g., Atlas_Core.Atlas_Default, Atlas_Core.PopupLayout).
  • Folder – Optional folder path within the module. Nested folders use / separator.
  • Variables – Optional page-level variables with default expressions. Variables can be used for conditional visibility and dynamic behavior.

Widget Tree

The widget tree inside { ... } defines the page content. Widgets are nested hierarchically. Each widget has:

  • A type keyword (e.g., DATAVIEW, TEXTBOX, ACTIONBUTTON)
  • A name (unique within the page, used for ALTER PAGE references)
  • Properties in parentheses (Key: value, ...)
  • Optional children in braces { ... }

Widget Types

Layout Widgets

WidgetDescriptionKey Properties
LAYOUTGRIDResponsive grid containerClass, Style, Width (FullWidth default, FixedWidth)
ROWGrid rowClass
COLUMNGrid columnClass
CONTAINERGeneric div containerClass, Style, DesignProperties
CUSTOMCONTAINERCustom container widgetClass, Style

Data Widgets

WidgetDescriptionKey Properties
DATAVIEWDisplays/edits a single objectDataSource
LISTVIEWRenders a list of objectsDataSource, PageSize
DATAGRIDTabular data display with columnsDataSource, PageSize, Pagination
GALLERYCard-based list displayDataSource, DesktopColumns, TabletColumns, PhoneColumns

Input Widgets

WidgetDescriptionKey Properties
TEXTBOXSingle-line text inputLabel, Attribute, Password, OnChange, OnEnter, OnLeave, OnEnterKeyPress (an action run when the user presses Enter in the box; the stored name OnEnterKeyPressAction is accepted too), SubmitBehaviour (OnEndEditing default, WhileEditing), SubmitOnInputDelay (ms, default 300), KeyboardType (the keyboard a native app opens: Default, NumberPad, DecimalPad, EmailAddress, PhonePad, URL)
TEXTAREAMulti-line text inputLabel, Attribute, OnChange, OnEnter, OnLeave, SubmitBehaviour, SubmitOnInputDelay
CHECKBOXBoolean toggleLabel, Attribute, OnChange, OnEnter, OnLeave
RADIOBUTTONSRadio button groupLabel, Attribute, OnChange, OnEnter, OnLeave
DATEPICKERDate/time selectorLabel, Attribute, OnChange, OnEnter, OnLeave
COMBOBOXDropdown selectorLabel, Attribute; association mode adds DataSource, CaptionAttribute; database mode optionsSourceDatabaseDataSource, CaptionAttribute, optionsSourceDatabaseValueAttribute; custom content as the mode’s body block (optionssourceassociationcustomcontent { … }, optionssourcedatabasecustomcontent { … })
FILEMANAGERFile upload/download, inside a data view on a System.FileDocument specializationLabel, Type (Upload, Download, Both default), MaxFileSize (MB, default 5), AllowedExtensions, ShowFileInBrowser

Display Widgets

WidgetDescriptionKey Properties
DYNAMICTEXTDisplay-only text bound to an attributeAttribute
LABELStudio Pro’s Label widget (Forms$Label): a fixed, translatable caption. describe emits it for existing labels; prefer DYNAMICTEXT for new textContent
IMAGEGeneric imageWidth, Height
STATICIMAGEFixed image from project resourcesWidth, Height
DYNAMICIMAGEImage from an entity attributeWidth, Height

Action Widgets

WidgetDescriptionKey Properties
ACTIONBUTTONButton that triggers an actionCaption, Action, ButtonStyle, Icon
LINKBUTTONHyperlink-styled actionCaption, Action, Icon

Structure Widgets

WidgetDescriptionKey Properties
HEADERPage header area–
FOOTERPage footer area (typically for buttons)–
CONTROLBARControl bar for data grids–
SNIPPETCALLEmbeds a snippetSnippet: Module.SnippetName
NAVIGATIONLISTNavigation sidebar list–

DataSource Types

The DataSource property determines how a data widget obtains its data:

DataSourceSyntaxDescription
ParameterDataSource: $ParamNameBinds to a page parameter or enclosing data view
DatabaseDataSource: DATABASE Module.EntityRetrieves from database
SelectionDataSource: SELECTION widgetNameListens to selection on another widget
MicroflowDataSource: MICROFLOW Module.MFNameCalls a microflow for data. Takes with (FormValidations: All|Widget|None) like a microflow action (default All); no other setting

Action Types

The Action property determines what happens when the widget is clicked. It is not a button-only property: a CONTAINER is clickable too and takes the same values, including the argument list.

ActionSyntaxDescription
SaveAction: save changesCommits and closes
CancelAction: cancel changesRolls back and closes
MicroflowAction: MICROFLOW Module.Name(Param = val)Calls a microflow
NanoflowAction: NANOFLOW Module.Name(Param = val)Calls a nanoflow
PageAction: PAGE Module.PageNameOpens a page
CloseAction: CLOSE PAGECloses the current page
DeleteAction: DELETEDeletes the context object
NothingAction: NOTHINGDeliberately no action — a decorative button, a card that is not clickable

The set is closed. Anything else in an action slot is an error (MDL-WIDGET28), and that includes a real action keyword missing its argument — Action: OPEN LINK with no URL, Action: SHOW PAGE with no page. Such a widget used to be written with no action at all: it rendered, carried its caption, and did nothing, while mxcli check, exec and mxbuild all reported success, because a no-action widget is perfectly legal Mendix. Write NOTHING when a control is genuinely meant to be inert, so that a dead one always means a mistake.

The same values serve OnClick: (an alias of Action:), OnChange: and a text box’s OnEnterKeyPress: — Studio Pro’s On enter key press, which runs when the user presses Enter in the box (a search field that searches on Enter):

TEXTBOX tbSearch (Label: 'Search', Attribute: SearchText,
  OnEnterKeyPress: CALL MICROFLOW Module.ACT_Search(Query = $currentObject))

Only a text box has that action — Mendix stores it on no other widget, a text area included — so on any other widget the key is refused with that reason.

Every input widget (text box, text area, date picker, check box, radio buttons, drop-down) also has Studio Pro’s On enter and On leave — focus moving into and out of the widget, not the Enter key — spelled OnEnter: and OnLeave:, with the same values. The stored names OnEnterAction:, OnLeaveAction: and OnEnterKeyPressAction: are accepted as the same properties; DESCRIBE prints the short ones.

A flow or page that takes no parameters may be called with an empty argument list, as a flow body writes it: Action: CALL MICROFLOW Module.Name() stores exactly what Action: CALL MICROFLOW Module.Name stores, and DESCRIBE writes it without the brackets. The same holds for a microflow or nanoflow data source and for USE FRAGMENT Name().

Action settings

Any action but NOTHING takes a with ( … ) list of the settings Studio Pro shows under the event:

SettingApplies toDefault
DisabledDuringExecution: true|falseevery actiontrue
ProgressBar: None|NonBlocking|Blockingmicroflow and nanoflow callsNone
ProgressMessage: 'text'microflow and nanoflow callsnone
Confirmation: 'question'microflow and nanoflow callsno confirmation
ProceedCaption: 'text', CancelCaption: 'text'a confirmation’s buttonsProceed, Cancel
Asynchronous: true|falsemicroflow callsfalse
FormValidations: All|Widget|Nonemicroflow callsAll
ACTIONBUTTON btnDelete (Caption: 'Delete',
  Action: CALL MICROFLOW Shop.ACT_Order_Delete(Order = $currentObject) with (
    ProgressBar: Blocking, ProgressMessage: 'Deleting…',
    Confirmation: 'Delete this order?', ProceedCaption: 'Delete', CancelCaption: 'Keep'))

A setting left out keeps its default, and DESCRIBE prints only the settings that differ from it. An unknown key, or a setting the action does not have, is an error. For CREATE OBJECT … THEN SHOW PAGE … the list goes at the end and belongs to the create action.

Return value mappings

A microflow or nanoflow call can map what the flow returns back onto the page — Studio Pro’s Return value mappings (Mendix 11.5+). The returns ( … ) list goes after the arguments and before with ( … ), one target = source per row:

DATAVIEW dvVehicle (DataSource: $Vehicle) {
  ACTIONBUTTON btnRefresh (Caption: 'Refresh',
    Action: CALL MICROFLOW Shop.ACT_Vehicle_Get returns (
      Brand = $ActionReturnValue/Brand,     -- an attribute of the returned object
      $stringResult = $ActionReturnValue,   -- the return value itself
      Brand = 'Demo brand'))                -- any expression
}
TargetMeansNeeds
Attr (bare)an attribute of the enclosing data container’s objectMendix 11.15 — mx 11.13 and 11.14 report CE7006 on it
$namea page variable (Variables: ( … ))Mendix 11.5

The source is $ActionReturnValue, $ActionReturnValue/Attr (the flow must return an object that has Attr), or any expression. DESCRIBE prints the stored mappings, and re-running a statement without the list removes them — the statement is the authority. A mapping DESCRIBE cannot spell (a path over an association) is printed as a comment under the widget, saying a re-run drops it.

A microflow or nanoflow action is a call: every parameter the flow declares needs an argument, or Mendix rejects the page with CE1571. An enclosing data container of the parameter’s type supplies it without one — but a data grid’s control bar does not, because it is not row-scoped. Pass the grid’s selection there, addressed by the widget’s own name:

DATAGRID dgOrders (DataSource: DATABASE FROM Sales.Order, Selection: Single) {
  COLUMN (Attribute: Number, Caption: 'Order #')
  CONTROLBAR {
    CONTAINER cShip (Class: 'command',
      Action: CALL NANOFLOW Sales.ACT_Ship(Order = $dgOrders)) {
      ACTIONBUTTON btnShip (Caption: 'Ship')
    }
  }
}

A SHOW PAGE in the control bar takes the selection the same way — Action: SHOW PAGE Sales.Order_Detail(Order = $dgOrders) opens the page with the selected row, and the button is disabled until a row is selected. In a grid with Selection, a SHOW PAGE in a column’s custom content may pass the grid’s selection by name as well, which is what Studio Pro stores there; $currentObject is the row.

A control bar takes its object from above its grid, but sits inside the grid, so the data view around the grid is an outer one there: $dvOrder from the control bar of a grid in data view dvOrder is valid.

mxcli check -p <app.mpr> reports a missing argument before mxbuild does.

ButtonStyle Values

Primary, Default, Success, Danger, Warning, Info.

DataGrid Columns

Inside a DATAGRID, child widgets define columns. Each column widget specifies:

PropertyValuesDescription
Attributeattribute nameThe entity attribute to display
CaptionstringColumn header (defaults to attribute name)
Alignmentleft, center, rightText alignment
WrapTexttrue, falseWhether text wraps
Sortabletrue, falseWhether column is sortable
Resizabletrue, falseWhether column is resizable
Draggabletrue, falseWhether column is draggable
Hidableyes, hidden, noColumn visibility control
ColumnWidthautoFill, autoFit, manualWidth mode
Sizeinteger (px)Manual width in pixels
Visibleexpression stringConditional visibility
Tooltiptext stringColumn tooltip

Common Widget Properties

These properties are available on most widget types:

PropertyDescriptionExample
ClassCSS class namesClass: 'card mx-spacing-top-large'
StyleInline CSSStyle: 'padding: 16px;'
DynamicClassesRuntime-computed CSS classes (expression; stacks on Class)DynamicClasses: if $currentObject/IsActive then 'is-active' else ''
EditableEdit control: Always, Never, or a condition expression (bare or quoted)Editable: NEVER or Editable: $currentObject/Locked = false
VisibleVisibility expressionVisible: '$showField'
DesignPropertiesAtlas design propertiesDesignProperties: ('Spacing top': 'Large')

Attributes of a Page or Snippet Parameter

A bare attribute name binds to the enclosing data container’s object. To bind an attribute of a page or snippet parameter instead, whatever container the widget is in, write $Param.Attr. This works for a pluggable widget’s attribute property set by its own key too, such as a Custom chart’s eventDataAttribute: $Ctx.EventData. The qualified name of another entity’s attribute (Module.Other.Attr) is refused, because stored without the parameter it is mx check CE7247.

An enclosing data view is named the same way: inside a data view nested in dvOuter, $dvOuter.Attr reads the outer data view’s object, and $dvOuter/Assoc/Attr reads over an association from it. This works on input widgets, on a pluggable widget’s attribute property (markdown md (stringAttribute: $dvOuter.Output)) and in an attribute-based visibility condition (Visible: $dvOuter.HasError in (true)). It is the form Studio Pro stores for these bindings.

Parameters

module.Name
The qualified name of the page (Module.PageName). The module must already exist.
Params: ( ... )
Optional page parameters. Each parameter has a $-prefixed name and an entity type.
Title: 'title'
The display title of the page. Required.
Layout: Module.LayoutName
The page layout. Must reference an existing layout. Required.
FOLDER 'path'
Optional folder within the module, as a clause after the name. Nested folders use /. The Folder: 'path' property is its deprecated alias (MDL-DEPR105).
Variables: ( ... )
Optional page variables with type and default expression.

Examples

Edit page with a data view and form fields:

CREATE PAGE MyModule.Customer_Edit
(
    Params: ( $Customer: MyModule.Customer ),
    Title: 'Edit Customer',
    Layout: Atlas_Core.PopupLayout
)
{
    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)
        }
    }
};

Overview page with a data grid:

CREATE PAGE Sales.Order_Overview FOLDER 'Orders'
(
    Title: 'Orders',
    Layout: Atlas_Core.Atlas_Default
)
{
    DATAGRID dgOrders (DataSource: DATABASE Sales.Order, PageSize: 20) {
        COLUMN (Attribute: OrderId, Caption: 'Order #')
        COLUMN (Attribute: OrderDate, Caption: 'Date')
        COLUMN (Attribute: Status, Caption: 'Status')
        COLUMN (Attribute: TotalAmount, Caption: 'Amount', Alignment: right)
        CONTROLBAR {
            ACTIONBUTTON btnNew (Caption: 'New Order', Action: SHOW PAGE Sales.Order_Edit, ButtonStyle: Primary)
        }
    }
};

Page with layout grid and containers:

CREATE PAGE MyModule.Dashboard
(
    Title: 'Dashboard',
    Layout: Atlas_Core.Atlas_Default
)
{
    LAYOUTGRID lgMain {
        ROW {
            COLUMN (Class: 'col-md-8') {
                CONTAINER cntRecent (Class: 'card') {
                    LISTVIEW lvRecent (DataSource: DATABASE MyModule.RecentActivity, PageSize: 5) {
                        DYNAMICTEXT txtDesc (Attribute: Description)
                    }
                }
            }
            COLUMN (Class: 'col-md-4') {
                CONTAINER cntStats (Class: 'card') {
                    DATAVIEW dvStats (DataSource: MICROFLOW MyModule.DS_DashboardStats) {
                        DYNAMICTEXT txtCount (Attribute: TotalCount)
                    }
                }
            }
        }
    }
};

Page with snippet call:

CREATE PAGE MyModule.Customer_Detail
(
    Params: ( $Customer: MyModule.Customer ),
    Title: 'Customer Detail',
    Layout: Atlas_Core.Atlas_Default
)
{
    DATAVIEW dvCustomer (DataSource: $Customer) {
        SNIPPETCALL snpHeader (Snippet: MyModule.CustomerHeader)
        TEXTBOX txtName (Label: 'Name', Attribute: Name)
        TEXTBOX txtEmail (Label: 'Email', Attribute: Email)
    }
};

Page with a gallery and selection-driven detail:

CREATE PAGE Sales.Product_Gallery
(
    Title: 'Products',
    Layout: Atlas_Core.Atlas_Default
)
{
    LAYOUTGRID lgMain {
        ROW {
            COLUMN (Class: 'col-md-6') {
                GALLERY galProducts (DataSource: DATABASE Sales.Product, PageSize: 12) {
                    DYNAMICTEXT txtName (Attribute: Name)
                    DYNAMICTEXT txtPrice (Attribute: Price)
                }
            }
            COLUMN (Class: 'col-md-6') {
                DATAVIEW dvDetail (DataSource: SELECTION galProducts) {
                    TEXTBOX txtName (Label: 'Product', Attribute: Name)
                    TEXTBOX txtDesc (Label: 'Description', Attribute: Description)
                }
            }
        }
    }
};

Page with page variables and conditional visibility:

CREATE PAGE MyModule.AdvancedForm
(
    Params: ( $Item: MyModule.Item ),
    Title: 'Advanced Form',
    Layout: Atlas_Core.Atlas_Default,
    Variables: ( $showAdvanced: Boolean = false )
)
{
    DATAVIEW dvItem (DataSource: $Item) {
        TEXTBOX txtName (Label: 'Name', Attribute: Name)
        ACTIONBUTTON btnToggle (Caption: 'Show Advanced', Action: CALL NANOFLOW MyModule.NAV_Toggle)
        CONTAINER cntAdvanced (Visible: '$showAdvanced') {
            TEXTAREA taNotes (Label: 'Notes', Attribute: Notes)
        }
        FOOTER {
            ACTIONBUTTON btnSave (Caption: 'Save', Action: SAVE CHANGES, ButtonStyle: Primary)
            ACTIONBUTTON btnCancel (Caption: 'Cancel', Action: CANCEL CHANGES)
        }
    }
};

Page with microflow data source:

CREATE PAGE Reports.MonthlySummary
(
    Title: 'Monthly Summary',
    Layout: Atlas_Core.Atlas_Default
)
{
    DATAVIEW dvReport (DataSource: MICROFLOW Reports.DS_GetMonthlySummary) {
        DYNAMICTEXT txtPeriod (Attribute: Period)
        DYNAMICTEXT txtRevenue (Attribute: TotalRevenue)
        DYNAMICTEXT txtOrders (Attribute: OrderCount)
    }
};

See Also

CREATE SNIPPET, ALTER PAGE, DROP PAGE, DESCRIBE PAGE, GRANT VIEW ON PAGE