Skip to content
Back to skills

Master Detail Pages

ASecurity

The master-detail page pattern in MDL: a selectable list beside a detail form driven by SELECTION. Use when building a selection-based screen rather than a plain list or form.

  • 128 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 26, 2026
ai-agentssqldatabase

Works with

  • cli

Security analysis

A100/100

Scanned October 4, 2026

npx -y skills add mendixlabs/mxcli --skill master-detail-pages --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Master Detail Pages?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Master Detail Pages
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mendixlabs-master-detail-pages/badge)](https://www.skillsdirectory.com/skills/mendixlabs-master-detail-pages)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: master-detail-pages
description: "The master-detail page pattern in MDL: a selectable list beside a detail form driven by SELECTION. Use when building a selection-based screen rather than a plain list or form."
---

# Master-Detail Pages

## Overview

Master-Detail is a common UI pattern showing:
- **Master list** (left): Selectable list of items (Gallery widget)
- **Detail form** (right): Form showing selected item details (DataView with SELECTION source)

## MDL Syntax

### Basic Structure

```sql
mdl 1;
create page Module.Entity_MasterDetail
(
  title: 'Entity Master-Detail',
  layout: Atlas_Core.Atlas_Default
)
{
  layoutgrid mainGrid {
    row {
      -- Master list (4 columns)
      column (desktopwidth: 4) {
        gallery entityList (datasource: database Module.Entity, selection: single) {
          template {
            dynamictext name (content: '{1}', contentparams: ({1} = Name), rendermode: H4)
          }
        }
      }

      -- Detail form (8 columns)
      column (desktopwidth: 8) {
        dataview entityDetail (datasource: selection entityList) {
          textbox txtName (label: 'Name', attribute: Name)

          footer {
            actionbutton btnSave (caption: 'Save', action: save changes, buttonstyle: success)
          }
        }
      }
    }
  }
};
```

### Key Components

#### 1. GALLERY Widget (Master List)

```sql
gallery widgetName (
  datasource: database from Module.Entity sort by Name asc,
  selection: single|multiple|none
) {
  template template1 {
    -- Widgets for each item
    dynamictext name (content: '{1}', contentparams: ({1} = AttrName), rendermode: H4)
  }
}
```

**Properties:**
- `datasource: database from entity sort by attr asc|desc` - Entity data source with optional sorting; `sort by Assoc/Attr asc` sorts over an association
- `selection: single` - Selection mode (Single for master-detail)
- Template content inside TEMPLATE widget (requires name)

#### 2. DataView with SELECTION Source

```sql
dataview widgetName (datasource: selection sourceWidgetName) {
  -- Form widgets
}
```

The `selection` source creates a binding to another widget's selection. When the user selects an item in the Gallery, the DataView displays that item.

#### 3. LISTVIEW Widget (Nested Data)

```sql
listview widgetName (datasource: database Module.Entity, PageSize: 10) {
  template template1 {
    -- Widgets for each associated item
  }
}
```

Used inside the detail form to show related/associated data.

**Nested list by association (to-many):** Use `datasource: $currentObject/Module.Assoc` (or the explicit `datasource: association path` form) on a **list** widget inside a parent DATAVIEW. Example: `datagrid lines (datasource: $currentObject/Order_OrderLine)` inside a `dataview dv (datasource: database Order)`.

**Referenced object by association (to-one) — "data from context":** To show a single *referenced* object's attributes, use the same `datasource: $currentObject/Module.Assoc` on a nested **DATAVIEW**. Its children bind to the referenced (destination) entity. Example: an inner `dataview dvEmployee (datasource: $currentObject/Expense_Employee) { textbox (attribute: Name) }` inside a `dataview dvExpense (datasource: $Expense)` shows the Expense's Employee. (A DataView association source is stored as a `Forms$DataViewSource` with an association-navigating EntityRef — do **not** confuse it with the list-widget `Forms$AssociationSource`; that one is invalid on a DataView.)

## Complete Example

```sql
mdl 1;
create page CRM.Customer_MasterDetail
(
  title: 'Customer Management',
  layout: Atlas_Core.Atlas_Default
)
{
  layoutgrid mainGrid {
    row {
      column (desktopwidth: 4) {
        dynamictext heading (content: 'Customers', rendermode: H3)
        gallery customerList (datasource: database from CRM.Customer sort by Name asc, selection: single) {
          template {
            dynamictext name (content: '{1}', contentparams: ({1} = Name), rendermode: H4)
            dynamictext email (content: '{1}', contentparams: ({1} = Email))
          }
        }
      }

      column (desktopwidth: 8) {
        dataview customerDetail (datasource: selection customerList) {
          dynamictext detailHeading (content: 'Customer Details', rendermode: H3)
          textbox txtName (label: 'Name', attribute: Name)
          textbox txtEmail (label: 'Email', attribute: Email)
          textbox txtPhone (label: 'Phone', attribute: Phone)

          footer {
            actionbutton btnSave (caption: 'Save', action: save changes, buttonstyle: success)
            actionbutton btnCancel (caption: 'Cancel', action: cancel changes)
          }
        }
      }
    }
  }
};
```

## Key Patterns

### Selection Binding

The core of master-detail is the selection binding:
1. Gallery has `selection: single` - enables single item selection
2. DataView uses `datasource: selection galleryName` - listens to Gallery selection
3. When user clicks an item in Gallery, DataView automatically updates

### Widget Names

The selection binding uses widget names to connect:
- Gallery widget name: `customerList`
- DataView references: `datasource: selection customerList`

### Template Content with ContentParams

Inside Gallery templates, use `contentparams` to reference current item attributes:
```sql
template template1 {
  dynamictext name (content: '{1}', contentparams: ({1} = Name), rendermode: H4)
  dynamictext email (content: '{1}', contentparams: ({1} = Email))
}
```

## Syntax Summary

| Element | Syntax |
|---------|-----------|
| Page properties | `(title: 'title', layout: Module.Layout)` |
| Widget name | Required after type: `gallery myGallery (...)` |
| Database source | `datasource: database from Module.Entity` |
| Selection binding | `datasource: selection widgetName` |
| Sort by | `datasource: database from entity sort by Name asc` |
| Sort over an association | `datasource: database from entity sort by Order_BillTo/City asc` — one `/` per hop, last segment is the attribute. Name the hop when two associations reach the same entity; inference cannot tell them apart (mendixlabs/mxcli#1152) |
| Where filter | `datasource: database from entity where [IsActive = true]` |
| Selection mode | `selection: single` |
| Attribute binding | `attribute: attributename` |
| Action binding | `action: save changes` |
| Button style | `buttonstyle: success` |
| Text content | `content: 'text'` with `contentparams: ({1} = attr)` |
| Render mode | `rendermode: H4` |
| Template content | `template template1 { ... }` |

## Related Skills

- [Overview Pages](../overview-pages/SKILL.md) - CRUD page patterns
- [Create Page](../create-page/SKILL.md) - Basic page syntax
- [ALTER PAGE/SNIPPET](../alter-page/SKILL.md) - Modify existing pages in-place (SET, INSERT, DROP, REPLACE)

## Implementation Notes

- Gallery is a pluggable widget (similar to DataGrid2)
- Selection binding uses `ListenTargetSource` in the Model SDK
- ListView is a built-in Mendix widget
- All widget properties use explicit `(key: value)` syntax

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…