It’s almost like a fake fact box and Placeholder bonus hack

In this video, I set out to control the column layout in Dynamics 365 Business Central. On top of that, I go on a video detour and finds a way to add placeholder texts to BC’s input fields.

https://youtu.be/pV_9WD0FXXE

Check out this video for a great way to explore and work interactively with Javascript in Business Central.


In this video, Erik demonstrates how to use JavaScript DOM manipulation to customize the Business Central UI layout for his support tool app. He tackles two problems: adjusting column widths to give more space to a code editor, and adding placeholder text to input fields for better discoverability — all through JavaScript control add-ins.

The Problem: Too Little Space, Too Much Scrolling

Erik’s support app has a three-column layout — one for code, one for a simple browser, and one for output. The problem is that the code area is too small, and the simple browser gets too much real estate. He wants to change the column width ratio from the default 50/50 split to something like 75/25.

After moving the result/output control below the main editor area (reducing its height by about 500 pixels), he turns his attention to the column widths.

Inspecting the DOM Structure

Using the browser’s developer tools (inspector), Erik identifies the key DOM elements that control the column layout:

  • A parent <div> with a class starting with single-column-group
  • A first column div with class ms-nav-layout-first-column
  • A last column div with class ms-nav-layout-last-column

Both columns default to 50% width. By manually editing the style attribute in the inspector — setting one to 75% and the other to 25% — he confirms the layout looks great. Now the challenge is doing this programmatically.

JavaScript Function: Change Column Widths

The key insight about JavaScript running inside Business Central is that your control add-in code executes inside an iframe. To manipulate elements outside the iframe (like the page’s column layout), you need to navigate up through the DOM using window.frameElement.

Here’s the approach Erik uses:

Step 1: Find the Column Group Container

Starting from the iframe’s frame element, use the closest() function to walk up the DOM tree and find the parent container:

var top = window.frameElement.closest('div[class^="single-column-group"]');

The closest() function searches upward through ancestors, and the selector uses ^= (starts with) to match the class name. This also ensures you’re manipulating the correct column group, even if there are multiple on the page.

Step 2: Find Each Column

From the parent container, use querySelector() to find each child column:

var column1 = top.querySelector('div[class^="ms-nav-layout-first-column"]');
var column2 = top.querySelector('div[class^="ms-nav-layout-last-column"]');

Step 3: Set the Widths

Finally, use setAttribute() to apply the new widths:

column1.setAttribute('style', 'width: ' + width1 + '%;');
column2.setAttribute('style', 'width: ' + width2 + '%;');

JavaScript’s loose typing automatically converts the decimal parameter to a string when concatenated. The full function is called from AL like this:

CurrPage.Editor.ChangeColumns(75, 25);

Bonus Hack: Adding Placeholder Text to Input Fields

With the layout fixed, Erik notices that two search fields on his page lack captions and are hard to identify. HTML5’s placeholder attribute is the perfect solution — it shows hint text inside an empty input field that disappears when you start typing.

Finding the Input Controls

The DOM structure for Business Central input fields looks something like this: a <div> with a controlname attribute wrapping the actual <input> element. The trick is to locate the wrapper div by its control name, then find the input within it.

One important gotcha Erik runs into: controlname is an attribute, not a CSS class. Initially he tried matching it as a class, which returned null. The correct selector uses attribute syntax:

function setPlaceholder(controlName, text) {
    var inputDiv = top.querySelector('div[controlname="' + controlName + '"]');
    var inputCtl = inputDiv.querySelector('input');
    inputCtl.setAttribute('placeholder', text);
}

Note that since there’s only one of each named control on the entire page, you can search from the top-level parent document. Also, because you’re reaching outside the iframe, you need to go through window.parent.document (or use the top variable already established).

Calling It from AL

CurrPage.Editor.SetPlaceholder('SearchCtl', 'Table Filter');
CurrPage.Editor.SetPlaceholder('FieldSearch', 'Field Filter');

The result: clean, descriptive placeholder text that appears in each input field when it’s empty, and vanishes as soon as the user types. A subtle but significant UX improvement.

The Source Code Context

While this video focuses on JavaScript DOM manipulation within a custom support tool, the source code provided shows a more traditional example of extending Business Central’s UI — adding a factbox to the Customer Card:

pageextension 50100 CustomerListExt extends "Customer Card"
{
    layout
    {
        addfirst(factboxes)
        {
            part(SalesOrders; "Our Factbox")
            {
                ApplicationArea = all;
                SubPageLink = "Sell-to Customer No." = field("No.");
            }
        }
    }
}

The factbox itself is a ListPart page displaying Sales Orders:

page 50100 "Our Factbox"
{
    PageType = ListPart;
    SourceTable = "Sales Header";
    SourceTableView = where("Document Type" = const(Order));
    Editable = false;
    Caption = 'Sales Orders!';
    ApplicationArea = all;

    layout
    {
        area(Content)
        {
            repeater(Rep)
            {
                field("No."; Rec."No.")
                {
                    trigger OnDrillDown()
                    begin
                        Page.RunModal(Page::"Sales Order", Rec);
                    end;
                }
                field("Order Date"; Rec."Order Date")
                {
                }
                field(Amount; Rec.Amount)
                {
                }
            }
        }
    }
}

This shows the standard AL approach to adding information panels in Business Central — real factboxes linked through SubPageLink. The JavaScript tricks Erik demonstrates in the video go beyond what AL alone can achieve, manipulating the rendered HTML to customize layout and UX.

Important Caveats

  • This is DOM manipulation of internal structures. Microsoft can change CSS class names, HTML structure, or rendering behavior at any time, which would break these hacks.
  • Erik explicitly notes this is a tool for himself. He’s comfortable with the risk of breakage because it’s a personal productivity tool, not a production app for customers.
  • If you’ve seen Erik’s earlier videos on the JavaScript Workbench, this is the same technique — using JavaScript control add-ins as an entry point to manipulate the surrounding Business Central page DOM.

Summary

Erik demonstrated two practical JavaScript DOM manipulation techniques for Business Central:

  1. Changing column widths — Navigate from the iframe to the parent page using window.frameElement.closest(), find the column containers, and set their width styles programmatically.
  2. Adding placeholder text — Locate input controls by their controlname attribute in the parent document, find the nested <input> element, and set the HTML5 placeholder attribute.

Both techniques leverage the fact that JavaScript control add-ins run inside an iframe, but can escape it to modify the surrounding page structure. While these are unsupported hacks that could break with platform updates, they showcase the power and flexibility of combining AL with JavaScript to create a polished, personalized development experience in Business Central.