A page layout controls how a record’s detail page is arranged: which tabs appear and what widgets they contain. Use definePageLayout() to declare a layout for an object you own, or definePageLayoutTab() to add a single tab to a layout that already exists (yours or a standard Diex one).

definePageLayout

Use this when you own the entire detail page — typically for a custom object you defined yourself.
src/page-layouts/example-record-page-layout.ts

Key points

  • type is one of 'RECORD_INDEX', 'RECORD_PAGE', 'DASHBOARD' or 'STANDALONE_PAGE'. Use 'RECORD_PAGE' to customize the detail view of a specific object.
  • objectUniversalIdentifier specifies which object this layout applies to.
  • Each tab defines a section of the page with a title, position, and layoutMode: VERTICAL_LIST for record pages and standalone pages, GRID for dashboards. In a VERTICAL_LIST tab, a single widget renders full-bleed and owns the whole tab; with several widgets they stack as cards. A GRID tab always lays its widgets out as cards on a 12-column grid, whatever their number, so pick VERTICAL_LIST when you want one widget to fill the page.
  • Set layoutMode explicitly. Omitting it gives you VERTICAL_LIST on a STANDALONE_PAGE and GRID everywhere else, which is rarely what you want on a record page.
  • Each widget inside a tab can render a front component, a relation list, or other built-in widget types.
  • position on tabs controls their order. Use higher values (e.g., 50) to place custom tabs after built-in ones.

Field widgets

A FIELD widget renders one field of the record. For relation fields it can also embed a list of related records:
  • fieldMetadataId takes the universal identifier of a field on the layout’s object.
  • fieldDisplayMode is one of 'FIELD', 'CARD', 'EDITOR', 'VIEW' or 'TABLE'. TABLE embeds a view listing the records of a one-to-many relation field.
  • nestedRelationFieldMetadataId is optional and takes the universal identifier of a one-to-many relation field on the relation target object, to list records two relation hops away (e.g. a Company page listing the opportunities of the company’s people, or a Person page listing the opportunities of the person’s company). The first hop can be a one-to-many or a many-to-one relation field, the second must be one-to-many (junction relations are not supported), and it requires fieldDisplayMode: 'TABLE' — combining it with any other display mode is a validation error, since a nested widget always renders as an embedded view.

definePageLayoutTab

Use this when you only want to add a tab to an existing layout — for example, an analytics tab on the standard Company page, or an AI summary tab attached to your own object’s layout.
src/page-layouts/example-extra-tab.ts

Key points

  • pageLayoutUniversalIdentifier is required and must point to a page layout that already exists at install time — either a standard Diex layout or one defined by your own app. Cross-app references to layouts owned by another installed app are not supported today. When the parent layout is missing, installation fails with a clear validation error.
  • For standard Diex layouts, import identifiers from diex-sdk/define:
    Each layout entry also exposes its tabs and their widgets, so you can reference any level:
    A short alias STANDARD_PAGE_LAYOUT is also available:
  • widgets are scoped to this tab only — they reference front components, views, etc. exactly like widgets defined inline in definePageLayout.
  • position controls ordering against existing tabs on the targeted layout. Pick a value that places your tab where you want it relative to built-in tabs.
  • Use this instead of definePageLayout when you only want to add to an existing layout. Use definePageLayout when you own the entire layout.