skill-pages
Skill115 starsChanged 10 days agoMITView on GitHub
AL page design patterns for Business Central. Use when creating Card, List, ListPart, Document pages, implementing page extensions, or designing UX layouts.
In this repository55 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- claude-plugin/CLAUDE.mdCLAUDE.md
- .github/copilot-instructions.mdCopilot instructions
- instructions/copilot-instructions.mdCopilot instructions
- agent-builderSkill
- al-agent-build-instructionsSkill
- al-agent-createSkill
- al-agent-instructionsSkill
- al-agent-taskSkill
- al-agent-testSkill
- al-buildSkill
- al-context-createSkill
- al-initializeSkill
- al-memory-createSkill
- al-pr-prepareSkill
- al-spec-createSkill
- architectSkill
- auditSkill
- conductSkill
- developSkill
- presalesSkill
- reviewSkill
- skill-agent-instructionsSkill
- skill-agent-task-patternsSkill
- skill-agent-toolkitSkill
- skill-al-review-pipelineSkill
- skill-apiSkill
- skill-contribution-assistantSkill
- skill-copilotSkill
- skill-debugSkill
- skill-estimationSkill
- skill-eventsSkill
- skill-migrateSkill
- skill-pagesSkill
- skill-performanceSkill
- skill-permissionsSkill
- skill-testingSkill
- skill-translateSkill
- specSkill
- triageSkill
- skill-agent-instructionsSkill
- skill-agent-task-patternsSkill
- skill-agent-toolkitSkill
- skill-al-review-pipelineSkill
- skill-apiSkill
- skill-contribution-assistantSkill
- skill-copilotSkill
- skill-debugSkill
- skill-estimationSkill
- skill-eventsSkill
- skill-migrateSkill
- skill-performanceSkill
- skill-permissionsSkill
- skill-testingSkill
- skill-translateSkill
The file
We split this skill into the rules it gives an agent
10 rules. About 0 are common, 4 are distinctive, and 6 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
6
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 191
Use UsageCategory = Lists for search/Tell Me discoverability
- Very specific: line 394
Add FactBoxes (area(FactBoxes)) for contextual info
- Distinctive: line 395
Add Notes and Links system parts
- Very specific: line 403
Add RunObject / RunPageLink for navigation actions
- Very specific: line 410
Update expressions in OnAfterGetRecord trigger
- Distinctive: line 416
Verify layout, navigation, and field behavior
- Distinctive: line 417
Test dynamic visibility and styling with different record states
- Very specific: line 431
Do NOT modify standard BC pages directly — use pageextension objects only
- Distinctive: line 432
Do NOT place more than 3-4 FlowFields on List pages (performance impact)
- Very specific: line 433
Do NOT skip ApplicationArea on any field or action
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Skill: AL Page Design
Purpose
Design and customize Business Central pages: Card, List, Document, Worksheet, and RoleCenter page types, page extensions with addafter/addbefore/modify, dynamic UI (visibility, styling), FastTab layout, promoted actions, and FactBoxes.
When to Load
This skill should be loaded when:
- Creating a new page (any type) for a custom or extended table
- Extending a standard BC page with custom fields, groups, or actions
- Designing a Document page with header-lines structure
- Implementing dynamic visibility, conditional styling, or field importance
- Optimizing page performance (FlowField limits, lazy loading)
Core Patterns
Pattern 1: Card Page
Single-record display with FastTab groups:
page 50100 "Contoso Project Card"
{
PageType = Card;
SourceTable = "Contoso Project";
Caption = 'Project Card';
UsageCategory = None; // accessed from list, not search
layout
{
area(Content)
{
group(General)
{
Caption = 'General';
field("No."; Rec."No.")
{
ApplicationArea = All;
Importance = Promoted; // visible in collapsed FastTab
}
field(Description; Rec.Description)
{
ApplicationArea = All;
Importance = Promoted;
}
field(Status; Rec.Status)
{
ApplicationArea = All;
StyleExpr = StatusStyleExpr;
}
field("Starting Date"; Rec."Starting Date")
{
ApplicationArea = All;
}
}
group(Details)
{
Caption = 'Details';
Visible = DetailsVisible; // dynamic visibility
field("Project Manager"; Rec."Project Manager")
{
ApplicationArea = All;
}
field(Budget; Rec.Budget)
{
ApplicationArea = All;
}
}
}
area(FactBoxes)
{
systempart(Notes; Notes) { ApplicationArea = All; }
systempart(Links; Links) { ApplicationArea = All; }
}
}
actions
{
area(Processing)
{
action(Release)
{
ApplicationArea = All;
Caption = 'Release';
Image = ReleaseDoc;
Promoted = true;
PromotedCategory = Process;
PromotedIsBig = true;
trigger OnAction()
begin
Rec.TestField(Status, Rec.Status::Open);
Rec.Validate(Status, Rec.Status::Released);
Rec.Modify(true);
end;
}
}
area(Navigation)
{
action(Entries)
{
ApplicationArea = All;
Caption = 'Ledger Entries';
Image = LedgerEntries;
RunObject = page "Contoso Project Entries";
RunPageLink = "Project No." = field("No.");
}
}
}
var
StatusStyleExpr: Text;
DetailsVisible: Boolean;
trigger OnAfterGetRecord()
begin
StatusStyleExpr := GetStatusStyle();
DetailsVisible := Rec.Status <> Rec.Status::Open;
end;
local procedure GetStatusStyle(): Text
begin
case Rec.Status of
Rec.Status::Open:
exit('Standard');
Rec.Status::Released:
exit('Favorable');
Rec.Status::Closed:
exit('Subordinate');
end;
end;
}Pattern 2: List Page
Multi-record display with filters and navigation:
page 50101 "Contoso Project List"
{
PageType = List;
SourceTable = "Contoso Project";
Caption = 'Projects';
UsageCategory = Lists;
ApplicationArea = All;
CardPageId = "Contoso Project Card";
Editable = false;
layout
{
area(Content)
{
repeater(Group)
{
field("No."; Rec."No.") { ApplicationArea = All; }
field(Description; Rec.Description) { ApplicationArea = All; }
field(Status; Rec.Status)
{
ApplicationArea = All;
StyleExpr = StatusStyleExpr;
}
field("Starting Date"; Rec."Starting Date") { ApplicationArea = All; }
// Limit FlowFields on list pages — max 3-4 for performance
field("Total Budget"; Rec."Total Budget") { ApplicationArea = All; }
}
}
}
var
StatusStyleExpr: Text;
trigger OnAfterGetRecord()
begin
StatusStyleExpr := GetStatusStyle();
end;
}List page rules:
- Set
Editable = false— use Card for editing - Set
CardPageIdfor drill-down navigation - Limit FlowFields to 3-4 maximum (each triggers a query per row)
- Use
UsageCategory = Listsfor search/Tell Me discoverability
Pattern 3: Document Page (Header + Lines)
page 50102 "Contoso Sales Document"
{
PageType = Document;
SourceTable = "Contoso Document Header";
Caption = 'Sales Document';
layout
{
area(Content)
{
group(General)
{
Caption = 'General';
field("No."; Rec."No.") { ApplicationArea = All; }
field("Customer No."; Rec."Customer No.")
{
ApplicationArea = All;
Importance = Promoted;
trigger OnValidate()
begin
CurrPage.Update(); // refresh lines after customer change
end;
}
field("Document Date"; Rec."Document Date") { ApplicationArea = All; }
}
part(Lines; "Contoso Document Subpage")
{
ApplicationArea = All;
SubPageLink = "Document No." = field("No.");
UpdatePropagation = Both; // sync header ↔ lines
}
}
}
}// Lines subpage
page 50103 "Contoso Document Subpage"
{
PageType = ListPart;
SourceTable = "Contoso Document Line";
Caption = 'Lines';
AutoSplitKey = true; // auto-increment Line No.
layout
{
area(Content)
{
repeater(Lines)
{
field(Type; Rec.Type) { ApplicationArea = All; }
field("No."; Rec."No.") { ApplicationArea = All; }
field(Description; Rec.Description) { ApplicationArea = All; }
field(Quantity; Rec.Quantity) { ApplicationArea = All; }
field("Unit Price"; Rec."Unit Price") { ApplicationArea = All; }
field("Line Amount"; Rec."Line Amount")
{
ApplicationArea = All;
Editable = false;
}
}
}
}
}Pattern 4: Page Extension
Extend standard BC pages without modifying them:
pageextension 50100 "Customer Card Ext" extends "Customer Card"
{
layout
{
addafter(General)
{
group(ContosoInfo)
{
Caption = 'Contoso Information';
field("Contoso Loyalty Points"; Rec."Contoso Loyalty Points")
{
ApplicationArea = All;
ToolTip = 'Total loyalty points for this customer.';
}
}
}
modify(Name)
{
// Change properties of existing fields
StyleExpr = NameStyleExpr;
}
moveafter("Post Code"; City) // reorder fields
}
actions
{
addlast(Processing)
{
action(ContosoCalculatePoints)
{
ApplicationArea = All;
Caption = 'Recalculate Points';
Image = Calculate;
Promoted = true;
PromotedCategory = Process;
trigger OnAction()
var
LoyaltyMgt: Codeunit "Contoso Loyalty Management";
begin
LoyaltyMgt.RecalculatePoints(Rec."No.");
CurrPage.Update(false);
end;
}
}
}
var
NameStyleExpr: Text;
trigger OnAfterGetRecord()
begin
NameStyleExpr := GetNameStyle();
end;
}Extension placement keywords:
addafter(AnchorField)/addbefore(AnchorField)— position relative to existing fieldaddlast(GroupName)/addfirst(GroupName)— at end/start of groupmodify(FieldName)— change properties of existing fieldmoveafter(Target; FieldToMove)/movebefore(Target; FieldToMove)— reorder
Pattern 5: Field Importance and Promoted Actions
Control visibility and prominence:
// Field importance — controls FastTab collapsed behavior
field(CriticalField; Rec.CriticalField)
{
ApplicationArea = All;
Importance = Promoted; // always visible (even when FastTab collapsed)
}
field(StandardField; Rec.StandardField)
{
ApplicationArea = All;
Importance = Standard; // visible when FastTab expanded (default)
}
field(RareField; Rec.RareField)
{
ApplicationArea = All;
Importance = Additional; // hidden unless "Show more" clicked
}// Promoted actions — modern actionref syntax (BC 22+)
actions
{
area(Processing)
{
action(Post) { Caption = 'Post'; Image = Post; }
action(Release) { Caption = 'Release'; Image = ReleaseDoc; }
}
area(Promoted)
{
group(Category_Process)
{
Caption = 'Process';
actionref(Post_Promoted; Post) { }
actionref(Release_Promoted; Release) { }
}
}
}Workflow
Step 1: Determine Page Type
| Need | PageType | Key Properties |
| Single record editing | Card | UsageCategory = None, has Card groups |
| Multi-record browsing | List | CardPageId, Editable = false, FlowField limits |
| Header + lines editing | Document | part() with ListPart subpage, UpdatePropagation |
| Batch data entry | Worksheet | Editable repeater, no Card drill-down |
| Dashboard/home page | RoleCenter | part() with cues, activities, headlines |
| Embed in another page | ListPart/CardPart | Used inside part() only |
Step 2: Design Layout
- Group related fields into FastTabs (
group()) - Set
Importance— Promoted for key fields, Additional for rare ones - Add FactBoxes (
area(FactBoxes)) for contextual info - Add Notes and Links system parts
- For Document pages, create the ListPart subpage with
AutoSplitKey
Step 3: Add Actions and Navigation
- Define actions in
area(Processing)andarea(Navigation) - Promote key actions using
area(Promoted)withactionref(BC 22+) - Set appropriate
Imageidentifiers - Add
RunObject/RunPageLinkfor navigation actions
Step 4: Implement Dynamic UI
Visible/Editableexpressions — control field/group visibility based on stateStyleExpr— conditional formatting (Favorable, Unfavorable, Attention, Subordinate, Strong)Enabled— disable actions based on record state- Update expressions in
OnAfterGetRecordtrigger
Step 5: Build and Test
- Build:
al_build - Publish:
al_publish(incremental) - Verify layout, navigation, and field behavior
- Test dynamic visibility and styling with different record states
References
- Page Types — Microsoft Docs
- Page Extension Object
- Actions Overview
- Promoted Actions (actionref)
- Field Importance
- Styling with StyleExpr
Constraints
- This skill covers page design, layout, extensions, and dynamic UI patterns
- Do NOT modify standard BC pages directly — use
pageextensionobjects only - Do NOT place more than 3-4 FlowFields on List pages (performance impact)
- Do NOT skip
ApplicationAreaon any field or action - API page design →
skill-api.md| Performance (FlowFields, SetLoadFields) →skill-performance.md| Page testing →skill-testing.md
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

