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 LAYOUT

Synopsis

CREATE [OR REPLACE] LAYOUT module.Name
(
    layouttype: 'Responsive',
    class: 'layout-atlas layout-atlas-responsive-topbar'
)
{
    SCROLLCONTAINER name [( layoutmode: 'Headline' | 'Sidebar' )] {
        REGION top | right | bottom | left | center ( region_properties ) {
            widgets
        }
    }
}

Description

Creates a layout — the frame every page renders inside: the topbar, the navigation sidebar, and the hole a page’s own content drops into. A page names one with its Layout property, and its widgets land in the layout’s Main placeholder.

A layout’s body uses the whole page widget vocabulary plus four element types that only a layout has: SCROLLCONTAINER, REGION, PLACEHOLDER and NAVIGATIONTREE (with MENUBAR for the topbar’s horizontal menu).

OR REPLACE rewrites an existing layout. To change one without rebuilding it, use ALTER LAYOUT instead — it edits the stored document and leaves alone anything it was not asked about, including widgets MDL cannot express.

Do not write into a Marketplace module

Mendix’s own guidance is “Do not change the supplied layouts. Either create a separate module with the custom layouts … or create your own.” A Marketplace update replaces the module wholesale and every local edit is gone, silently.

CREATE LAYOUT refuses a Marketplace target for that reason:

Error: layout Atlas_Core.T2: Atlas_Core is a marketplace module — a layout
written there is overwritten by the next module update. Create the layout in a
module of your own (Mendix's own guidance) and point pages at it with
ALTER PAGE … SET LAYOUT.

The usual starting point is a copy of an Atlas layout. DESCRIBE LAYOUT emits re-executable MDL, so describe → rename → run is the copy operation:

mxcli -p app.mpr -c "describe layout Atlas_Core.Atlas_Default" > mine.mdl
# change the qualified name to your own module, then:
mxcli exec mine.mdl -p app.mpr

Read the describe output before running it. A widget MDL cannot express is emitted as a comment ending -- NOT re-executable, naming exactly what a re-run would drop.

Atlas’s responsive sidebar toggle is the sidebartoggle widget, so a copied layout keeps its slide-in navigation on phones and tablets:

sidebartoggle sidebarToggle3 (
  Tooltip: 'Toggle Menu', ButtonStyle: Primary,
  Icon: 'Atlas_Core.Atlas_Filled.navigation-menu', Class: 'toggle-btn'
)

It takes an action button’s Caption, Tooltip, ButtonStyle and Icon, and RenderMode: Link to render as a link; it has no Action.

The phone and tablet layouts keep their header bar in a layoutheader, whose two sides are spelled like a scroll container’s regions:

layoutheader header1 {
  region left { sidebartoggle sidebarToggle2 (RenderMode: Link, Icon: 'Atlas_Core.Atlas_Filled.navigation-menu') }
  region right { placeholder HeaderRight }
}

A native layout keeps three things beside its content tree: the placeholder on the header’s right, whether the bottom bar shows, and the sidebar.

create layout MyModule.Native_SideMenu (layouttype: 'Default', showbottombar: true) {
  placeholder Main
  region header { placeholder Header }
  region sidebar { placeholder Placeholder1 }
};

Parameters

module.Name

The qualified name of the layout (Module.LayoutName). Must be a module you own.

layouttype

Required. Omitting it is an error, not a default: Error: layout needs a layouttype.

PlatformValues
WebResponsive, Phone, Tablet, ModalPopup
NativeDefault, Popup

The two sets are disjoint, so the platform is inferred from the type — there is no separate native: flag to contradict it.

class

The layout’s own CSS class. Not decoration — Atlas scopes around two dozen of its layout rules to .layout-atlas and its variants, and every Atlas layout with chrome carries one. A layout written without it builds cleanly, passes mx check, and renders with no topbar bar and no sidebar rail.

ShapeClass
Topbar navigationlayout-atlas layout-atlas-responsive-topbar
Sidebar navigationlayout-atlas layout-atlas-responsive-default
Popup(none — PopupLayout is bare)
style

Inline CSS on the layout element.

Layout

The layout this one is built on — see A layout built on another layout.

layouttype, class, style and Layout are the only header properties. Anything else is an error rather than an ignored key:

Error: layout MyModule.T1: unknown property "bogus" (a layout header takes
layouttype, class, style and layout; which placeholder is "main" is set by
naming one Main, not by a property)

A layout built on another layout

Studio Pro lets a layout wrap another one rather than have a tree of its own (ConversationalUI’s Layout_MasterBase wraps Atlas_Core.Atlas_Default). Name the outer layout with Layout: and write the body exactly as a page body: PLACEHOLDER X { … } fills the outer layout’s placeholder X, and bare widgets fill its Main. The placeholders the new layout declares for its own pages go inside those blocks, bodiless as anywhere else in a layout:

CREATE OR MODIFY LAYOUT MyModule.Layout_Framed (
  layouttype: 'Responsive',
  Layout: Atlas_Core.Atlas_Default
) {
  PLACEHOLDER Main {
    CONTAINER banner (Class: 'card') {
      DYNAMICTEXT heading (Content: 'Framed area', RenderMode: H3)
    }
    PLACEHOLDER Main
  }
};
  • The layout still needs exactly one declared Main (CE0848), counted inside the blocks.
  • A block naming a placeholder the outer layout does not declare is refused; mxbuild would report it as CE1613.
  • Only web layouts can be built on another layout.
  • DESCRIBE LAYOUT prints this form, with one block per stored argument.

Scroll container properties

PropertyValuesNotes
layoutmodeHeadline, SidebarThe frame. Headline runs the top region across the full width and starts the left one under it; Sidebar runs the left region the full height and puts the top bar beside it (Atlas’s Atlas_SideBar and Atlas_TopBar). Unset is Headline, and DESCRIBE LAYOUT prints it only when it is Sidebar. Change it on a stored layout with ALTER LAYOUT … { SET (layoutmode: 'Sidebar') ON layoutContainer; }

Region properties

PropertyValuesNotes
sizeintegerUnset is Studio Pro’s 200
sizemodeFixed, Pixels, AutoUnset is Auto
togglemodeNone, PushContentAside, SlideOverContent, ShrinkContentInitiallyOpen, ShrinkContentInitiallyClosedHow a SIDEBARTOGGLE opens and closes the region. Unset is None
classCSS classe.g. region-topbar, region-content. The only appearance property a region stores: style on one is refused (MDL-WIDGET52)

The four elements only a layout has

ElementMDLNotes
Scroll containerSCROLLCONTAINER name { … }The layout’s root. Its children are regions, never widgets
RegionREGION top | right | bottom | left | centerFive named slots, not a list. One region per slot
PlaceholderPLACEHOLDER MainThe hole a page’s content goes into. No properties, no body
Navigation treeNAVIGATIONTREE name (profile: 'Responsive')The sidebar menu — vertical
Menu barMENUBAR name (profile: 'Responsive')The topbar menu — horizontal
Simple menu barSIMPLEMENUBAR name (menu: Module.Menu [, orientation: Vertical])A phone layout’s bottom bar, as Atlas’s Phone_BottomBar has it. orientation defaults to Horizontal

Every menu widget renders either a navigation profile (profile: 'Responsive') or a menu document (menu: Module.Menu, created with CREATE MENU) — the two are alternatives for the same slot, and naming both is refused. With neither, the Responsive profile is used.

Examples

A topbar layout, which is the shape mxcli new scaffolds:

CREATE OR MODIFY LAYOUT MyModule.App_Default
(
    layouttype: 'Responsive',
    class: 'layout-atlas layout-atlas-responsive-topbar'
)
{
    SCROLLCONTAINER layoutContainer {
        REGION top (size: 60, sizemode: 'Fixed', class: 'region-topbar') {
            MENUBAR mainMenu (profile: 'Responsive')
        }
        REGION center (class: 'region-content') {
            PLACEHOLDER Main
        }
    }
};

A sidebar layout, with a navigation tree in the left region running the full height (layoutmode: 'Sidebar'; leave it out and the top region spans the page):

CREATE LAYOUT MyModule.App_Sidebar
(
    layouttype: 'Responsive',
    class: 'layout-atlas layout-atlas-responsive-sidebar'
)
{
    SCROLLCONTAINER layoutContainer (layoutmode: 'Sidebar') {
        REGION left (size: 232, sizemode: 'Pixels', class: 'region-sidebar') {
            NAVIGATIONTREE navMenu (profile: 'Responsive')
        }
        REGION center (class: 'region-content') {
            PLACEHOLDER Main
        }
    }
};

A page then names the layout, and its widgets land in Main:

CREATE PAGE MyModule.Dashboard
(
    Title: 'Dashboard',
    Layout: MyModule.App_Default
)
{
    CONTAINER cntMain {
        DYNAMICTEXT txtWelcome (Content: 'Welcome')
    }
};

Notes

  • A layout must declare at least one placeholder. Without one a page’s content has nowhere to go, and the statement is refused: layout "X" declares no placeholder.
  • Name one placeholder Main. Forms$Layout has no property recording which placeholder is the main one — the convention is the mechanism, and all 22 layouts Atlas ships follow it. There is deliberately no mainplaceholder: property: writing the underlying key produces a layout that builds cleanly and that Studio Pro cannot open.
  • A placeholder’s name is API. Pages bind to it as Module.Layout.Name. Renaming one unbinds every page that used it — those pages still build, and their content vanishes.

See Also

ALTER LAYOUT, CREATE PAGE, ALTER PAGE / ALTER SNIPPET