App-Embedded Pictures make your UI Pretty

In this video, I show how you can have an embedded picture in your app file and use that on pages in AL. Check it out:


In this video, Erik demonstrates how to embed pictures directly inside a Business Central app file and display them on a page using a control add-in. This technique avoids external image dependencies and security concerns by serving the image from the same web server as Business Central itself.

Why Embed Pictures in Your App?

There are several ways to display images on a Business Central page, but embedding them directly inside the app file has distinct advantages:

  • No external dependencies — the image is bundled within the .app file itself
  • No security issues — in locked-down client environments that only communicate with Microsoft servers, externally-hosted images may be blocked
  • Consistent delivery — the image is served from the same web server that serves Business Central

Erik was inspired to create this tutorial after a conversation with Steve, another MVP, who saw a logo displayed on one of Erik’s registration screens (from either the Symbologic Designer or the Toolbox) and asked how it was done. It turned out to be a common question — and the solution isn’t as complicated as you might think.

Step 1: Create the Control Add-In

The foundation of this technique is a control add-in. In Business Central, a control add-in is essentially rendered as an iframe. BC uses iframes to isolate content, and we can leverage this to display our embedded image.

The control add-in definition needs to declare the image file, set sizing properties, and reference a startup script:

controladdin LogoPicture
{
    Images = 'pictures/logo.png';
    StartupScript = 'startup.js';
    VerticalStretch = true;
    HorizontalStretch = true;
    RequestedHeight = 300;
}

A few key points about this definition:

  • Images — this tells BC to embed the specified image file into the app package. The path here must match what you reference later in JavaScript.
  • StartupScript — this is JavaScript that runs automatically when the page opens (as opposed to Scripts, which is for library code you call manually).
  • RequestedHeight — since BC doesn’t support flow-based layout for control add-ins, you need to hard-code the height. This means if you have images of different sizes, you’ll likely need multiple control add-in definitions.
  • VerticalStretch / HorizontalStretch — set to true to allow the control to fill available space.

Erik noted it would be a great improvement if Microsoft allowed specifying the requested height at runtime or layout time rather than requiring it to be hard-coded in the control add-in definition.

Step 2: Write the Startup JavaScript

When BC creates the iframe for your control add-in, it also provides a div inside that iframe with the ID controlAddIn. Your JavaScript needs to insert the image HTML into this div.

var controlAddIn = document.getElementById('controlAddIn');
var url = Microsoft.Dynamics.NAV.GetImageResource('pictures/logo.png');
var imgHtml = '<img style="display:block;margin-left:0px;margin-right:auto;width:100%;" src="' + url + '" />';
controlAddIn.insertAdjacentHTML('beforeend', imgHtml);

Let’s break down what’s happening:

  1. Get the containerdocument.getElementById('controlAddIn') retrieves the div that BC provides inside the iframe.
  2. Get the image URLMicrosoft.Dynamics.NAV.GetImageResource() is the critical function here. Since we have no idea what the actual URL of the embedded image will be at runtime, this BC-provided JavaScript function resolves the path for us. The path you pass must exactly match the path declared in the Images property of the control add-in.
  3. Build the HTML — we create an <img> tag with inline styles to make it fill the width of the page.
  4. Insert the HTMLinsertAdjacentHTML('beforeend', ...) adds the image markup to the div. Note: the first parameter specifying the insertion position is required — Erik initially forgot it and got an error: “Failed to execute insertAdjacentHTML on element: two arguments required but only one present.”

The inline styles ensure the image displays nicely:

  • display: block — renders the image as a block element
  • margin-left: 0px; margin-right: auto — positions the image
  • width: 100% — fills the entire horizontal space, which makes sense since adding a control at the top of the content area always takes up the full page width anyway

Step 3: Add the Control to a Page

To display the control add-in on a page, you use a page extension. Here’s the slightly counterintuitive part: even though you’ve defined a control add-in, what you add to the layout is declared as a user control:

pageextension 50123 CustomerCardExt extends "Customer Card"
{
    layout
    {
        addfirst(Content)
        {
            usercontrol(LogoBanner; LogoPicture)
            {
                ApplicationArea = All;
            }
        }
    }
}

Using addfirst(Content) places the image at the very top of the page’s content area, creating a banner effect above all the existing fields and groups.

File Organization and Path Matching

One important detail: the path you specify in the control add-in’s Images property must match what you pass to GetImageResource() in JavaScript. If you organize your images into a subfolder:

// In the control add-in definition:
Images = 'pictures/logo.png';

// In the JavaScript:
Microsoft.Dynamics.NAV.GetImageResource('pictures/logo.png');

If these paths don’t match, the image won’t resolve correctly.

Impact on App File Size

Be aware that embedding images increases your app file size. In Erik’s example, the logo was 133 KB, and the resulting app file was 272 KB total. For a simple logo or banner this is perfectly reasonable, but keep this in mind if you’re considering embedding many large images.

The Final Result

In total, this technique requires just three small pieces:

  1. A control add-in definition (~8 lines of AL) that declares the image, the startup script, and sizing properties
  2. A startup JavaScript file (~4 lines) that retrieves the image URL and inserts it into the DOM
  3. A page extension that adds the user control to whatever page you want the image displayed on

The image is served directly from the Business Central web server — whether that’s the cloud or an on-premises installation — making it reliable and secure without any external dependencies.

Summary

Embedding pictures in your Business Central app is a straightforward technique that combines a control add-in, a few lines of JavaScript, and the Microsoft.Dynamics.NAV.GetImageResource() function. The key takeaways are: declare your image in the control add-in’s Images property, use the BC-provided API to resolve the runtime URL, ensure your paths match between the AL definition and JavaScript, and remember that insertAdjacentHTML requires a position parameter. While the hard-coded height is a current limitation, this approach gives you a clean, self-contained way to add logos, banners, and other visual elements to your Business Central pages.