How about we show some progress in this bar?

Using a progress bar to inform users that the system is working is a great way to improve how long-running processes are perceived. This time I take a look at a progress bar found on GitHub.

https://youtu.be/O7UVaHqQgdE

In this video, Erik explores how to create and display a progress bar in AL for Business Central. He starts by looking at an existing open-source project — Henrik’s BCL Toolbox on GitHub — that already includes a progress bar implementation using the classic Dialog window approach. He then goes further by demonstrating a custom control add-in approach that renders a proper HTML/CSS progress bar directly on a page.

The Challenge: Progress Bars in Business Central

Progress bars were something that worked well in the old NAV C/AL world, but Microsoft never fully ported that visual functionality to AL in Business Central. The built-in Dialog type supports a window with text updates, but there’s no native progress bar control. This leaves developers with two main approaches: leveraging the Dialog window creatively, or building a custom control add-in.

Approach 1: Henrik’s BCL Toolbox (Dialog-Based Progress)

Erik first looks at Henrik’s BCL Toolbox, an open-source project on GitHub. The toolbox includes a “Dialogue Helper” codeunit that wraps the standard Dialog functionality with useful features like estimated time remaining, percentage display, and a text-based progress bar built from special characters.

The key functions in Henrik’s implementation are:

  • OpenWindow — Opens a dialog window with a customizable string and an option to show estimated time remaining
  • UpdateWindow — Updates the progress with a counter and total number of records (has multiple overloads)
  • CloseWindow — Closes the dialog when processing is complete

A simple usage looks like this:

// Declare the codeunit variable
var Henrik: Codeunit "TBHLG Dialogue Helper";

// Open the window with a placeholder and estimated time
Henrik.OpenWindow('Important work #1', true);

// Loop through your work
for i := 1 to 1200 do begin
    Henrik.UpdateWindow(i, 1200);
    Sleep(5);
end;

// Close when done
Henrik.CloseWindow();

Interesting Implementation Details

Looking inside Henrik’s code, Erik highlights several smart design decisions:

  • GuiAllowed checks — The dialog calls are wrapped so they won’t break when running in background sessions, job queues, or task schedulers
  • Update frequency throttling — The code checks whether at least one second has passed since the last UI update before refreshing, preventing excessive screen updates
  • Early exit pattern — The update function uses multiple early exits: if less than a second since last update, if nothing has changed, if the time estimate hasn’t changed in two seconds, etc. This makes the code very readable
  • Time estimation — It calculates estimated time remaining and estimated end time based on elapsed time and progress percentage

The text-based progress bar itself is built using PadStr and CopyStr with special ASCII block characters. Erik experimented with replacing these with emoji characters (like smiley faces) but ran into issues because PadStr doesn’t handle double-byte/multi-byte characters well — a limitation worth noting if you want to customize the appearance.

Approach 2: Custom Control Add-In (HTML/CSS Progress Bar)

For a more visually appealing progress bar, Erik also demonstrates a control add-in approach that renders an actual HTML progress bar directly on a Business Central page. This gives you full control over the styling and behavior.

The Control Add-In Definition

controladdin MyProgressBar
{
    Scripts = 'script.js';
    StartupScript = 'startup.js';
    StyleSheets = 'progress.css';
    MinimumHeight = 50;
    MaximumHeight = 50;
    HorizontalStretch = true;

    event IAmReady();

    procedure SetProgress(Progress: Integer);
}

The add-in exposes a single procedure SetProgress that accepts an integer percentage, and an event IAmReady that fires when the control has finished loading in the browser.

The Startup Script

var addin = document.getElementById('controlAddIn');
addin.innerHTML = '<div id="myProgress"><div id="myBar">0%</div></div>';

var CurrentProgress = 0;

Microsoft.Dynamics.NAV.InvokeExtensibilityMethod('IAmReady',[]);

This creates the HTML structure for the progress bar and then signals back to AL that the control is ready to receive data.

The Progress Update Script

function SetProgress(progress) {
    var elem = document.getElementById("myBar");
    elem.style.width = progress + "%";
    elem.innerHTML = progress + "%";
}

The commented-out code in the source suggests Erik was experimenting with animated transitions (incrementing/decrementing one percent at a time), but the final version sets the width directly for simplicity.

CSS Styling

#myProgress {
    width: 100%;
    background-color: #ddd;
}
  
#myBar {
    width: 0%;
    height: 30px;
    background-color: #04AA6D;
    text-align: center;
    line-height: 30px;
    color: white;
}

A clean, simple green progress bar on a gray background — easily customizable to match your branding.

Integrating with a Page

Erik demonstrates embedding this on the Job Card page using a page extension with a field to control the progress value:

pageextension 50100 "My Job" extends "Job Card"
{
    layout
    {
        addlast(General)
        {
            field(MyProgress; Rec.MyProgress)
            {
                ApplicationArea = All;
                trigger OnValidate()
                begin
                    CurrPage.bar.SetProgress(Rec.MyProgress);
                end;
            }
            usercontrol(bar; MyProgressBar)
            {
                ApplicationArea = All;
                trigger IAmReady()
                begin
                    CurrPage.bar.SetProgress(Rec.MyProgress);
                end;
            }
        }
    }
}

The progress value is stored in a custom field on the Job table via a table extension:

tableextension 50100 "My Job" extends Job
{
    fields
    {
        field(50100; MyProgress; Integer)
        {
            Caption = 'Progress';
        }
    }
}

When the user changes the progress value or when the page loads, the control add-in updates the visual bar accordingly.

Which Approach Should You Use?

  • Dialog-based (Henrik’s approach) — Best for long-running processes where you want to show progress during a batch operation. Works server-side, handles background sessions gracefully, and includes time estimation out of the box.
  • Control add-in approach — Best for showing persistent progress on a page (like project completion percentage). Gives you full visual control with HTML/CSS, but only works in the web client with a UI.

Conclusion

Business Central may not have a built-in progress bar control, but there are solid options available. Henrik’s BCL Toolbox on GitHub provides a battle-tested Dialog-based solution with smart features like time estimation and throttled updates. For scenarios where you need a visual progress bar embedded directly on a page, a control add-in with HTML and CSS gives you complete flexibility. Both approaches are relatively straightforward to implement, and the open-source community around Business Central makes it easy to find and build on existing solutions rather than starting from scratch.