Sometimes I get the most awesome suggestions and ideas from viewers. Check out this video for a great hack do create fast, on-the-fly ControlAddins:

This video showcases a clever trick submitted by viewer Aiden: using the built-in WebPageViewer control add-in that already ships with Business Central to create quick interactive UI elements — no custom control add-in development required. Erik walks through two examples: a simple clickable button and a full text area with change detection, all in under 20 lines of AL code.
The “Poor Man’s Control Add-In” Concept
Normally, if you want to add custom interactive UI elements to a Business Central page — buttons with JavaScript behavior, text areas, or other HTML controls — you need to create a proper control add-in. That means writing a separate add-in definition, creating JavaScript startup scripts, packaging everything together, and deploying it.
But as viewer Aiden pointed out, Business Central already includes a built-in control add-in called Microsoft.Dynamics.Nav.Client.WebPageViewer. This control is designed to display web content, but it can also be repurposed to inject arbitrary HTML and JavaScript directly from AL code. The key insight is that it provides:
- A
SetContentmethod that accepts raw HTML - A
ControlAddInReadytrigger that fires when the control is loaded - A
Callbacktrigger that can receive data back from JavaScript
By combining these, you can create interactive controls without ever leaving your AL file.
Example 1: A Simple Button
The first example demonstrates the simplest possible case — a button that triggers a callback when clicked. Inside a page extension on the Customer List, you add a usercontrol using the WebPageViewer and inject a button via SetContent:
CurrPage.clickme.SetContent(
'<button onclick="window.parent.WebPageViewerHelper.TriggerCallback(''clicked'');">Click Me!</button>'
);
The magic happens with window.parent.WebPageViewerHelper.TriggerCallback(). This is the JavaScript function that communicates back to AL, invoking the Callback trigger on the control. Whatever string you pass as a parameter becomes the data value in the AL trigger.
One thing Erik discovered during the live demo: JavaScript is case-sensitive. The method is TriggerCallback with a lowercase “b” — not TriggerCallBack. AL developers accustomed to case-insensitive code need to be careful here.
Example 2: A Text Area with Change Detection
Aiden’s original example was more sophisticated — a full text area that sends its content back to AL whenever the user changes focus away from it. This is the version that made it into the final code:
pageextension 50100 CustomerListExt extends "Customer List"
{
layout
{
addfirst(content)
{
usercontrol(clickme; "Microsoft.Dynamics.Nav.Client.WebPageViewer")
{
ApplicationArea = all;
trigger ControlAddInReady(callbackUrl: Text)
begin
CurrPage.clickme.SetContent(
StrSubstNo(
'<textarea Id="TextArea" style="width:100%%;height:100%%;resize: none; font-size: 10.5pt !important; font-family: monospace;" OnChange="window.parent.WebPageViewerHelper.TriggerCallback(document.getElementById(''TextArea'').value)">%1</textarea>',
'Erik Hougaard\YouTube Video\hougaard.com\Simple Object Designer'
)
);
end;
trigger Callback(data: Text)
begin
message(data);
end;
}
}
}
}
Let’s break down what’s happening in that HTML string:
- A
<textarea>element is created with an ID of “TextArea” - Inline CSS styling makes it fill the available space, disables resizing, and sets a monospace font — giving it a code-editor feel
- The
OnChangeevent fires when the textarea loses focus after its content has been modified. It grabs the current value usingdocument.getElementById('TextArea').valueand passes it toTriggerCallback StrSubstNois used to inject initial content into the textarea via the%1placeholder
The behavior is intuitive: you can type freely inside the text area, and as soon as you click outside of it (the control loses focus), the OnChange event fires, sending the entire content back to AL where it arrives in the Callback trigger’s data parameter.
When to Use This Approach
This technique is ideal for quick, lightweight scenarios where you need a small amount of interactivity without the overhead of building a full custom control add-in. Think of it as the prototyping tool for control add-ins — or even the final solution for simple cases.
Good use cases include:
- Quick action buttons that trigger AL logic
- Simple text input areas for multi-line or formatted text
- Displaying styled HTML content inline on a page
- Rapid prototyping of control add-in concepts
However, if your requirements grow more complex — if you need multiple callbacks, external library dependencies, complex state management, or reusable components — then a proper custom control add-in is still the way to go.
Conclusion
This is an elegant trick that leverages an existing, built-in control to avoid the ceremony of creating a custom control add-in. The entire solution lives in a single AL file with no additional JavaScript files, no control add-in definition objects, and no extra deployment steps. For quick-and-dirty interactive elements on Business Central pages, the “Poor Man’s Control Add-In” approach using the WebPageViewer is a handy tool to keep in your back pocket. Full credit to Aiden for the original idea — a great example of the kind of practical insights that come from the community.