Hacking the new Business Central Border shine

Business Central 2023 Wave 1 contains a fancy animation on the new GPT marketing text FactFox. In this video, I try to unlock the animation to work elsewhere, check it out:

https://youtu.be/GfkadJ0dufE

In this video, Erik explores a fun CSS animation trick in Business Central — the shiny border effect that Microsoft introduced with the new GPT-related features. He reverse-engineers how the animation works and demonstrates how to trigger it on any control using a custom control add-in and some JavaScript.

The Shiny Border Effect

If you’ve seen the new GPT/Copilot features in Business Central, you may have noticed a fancy animated border shine effect that appears when you hover over certain elements. Erik was curious about how this worked and whether it could be applied to other controls.

Using the browser’s developer tools, Erik inspects the element and discovers that the animation is controlled via CSS classes. When you hover over the element, a class like borderShine-271 gets added to the element, which triggers the CSS animation. When the animation completes, the class is removed.

How CSS Animation Classes Work in BC

A typical pattern for CSS animations is:

  1. Add a CSS class to an element to trigger the animation
  2. Listen for the animation end event
  3. Remove the class so the animation can be triggered again

Erik demonstrates this directly in the browser console. By selecting an element using document.querySelector with the controlname attribute, he can manually add and remove the border shine class:

// Select an element by its control name attribute
document.querySelector("[controlname='Description']")

// Add the border shine class to trigger the animation
element.classList.add('borderShine-271')

// Remove it so it can be triggered again
element.classList.remove('borderShine-271')

The Obfuscation Problem

There’s a catch: Microsoft obfuscates their CSS class names. The number suffix on borderShine-271 is dynamic and changes between builds and sessions. There are roughly 190 stylesheets on an average BC page, so you can’t just hardcode the class name. You need to search for it programmatically.

Building the Solution

Erik builds a small AL extension to trigger the border shine effect from a button on the Item Card. The solution consists of three parts:

The Control Add-in Definition

A simple control add-in that loads a JavaScript file and exposes a single procedure:

controladdin BorderAddIn
{
    Scripts = 'script.js';
    procedure DoIt();
}

The Page Extension

A page extension on the Item Card that adds the user control and a promoted action button to trigger the effect:

pageextension 50100 ItemListExt extends "Item Card"
{
    layout
    {
        addLast(content)
        {
            usercontrol(Border; BorderAddIn)
            {
                applicationArea = all;
            }
        }
    }
    actions
    {
        addfirst(processing)
        {
            action(Test)
            {
                Caption = 'Test';
                ApplicationArea = all;
                Promoted = true;
                PromotedCategory = Process;
                PromotedIsBig = true;
                PromotedOnly = true;
                ToolTip = 'Test';

                trigger OnAction()
                begin
                    CurrPage.Border.DoIt();
                end;
            }
        }
    }
}

The JavaScript

This is where the magic happens. Since the JavaScript runs inside an iframe, it needs to reach up to the parent window to access the stylesheets. It then loops through all stylesheets and their CSS rules to find the one whose selector starts with .borderShine-. Once found, it adds that class to the target control:

function DoIt()
{
    var currentSheet = null;
    var i = 0;
    var j = 0;
   
    // Loop through styleSheets on the parent page
    for(i = 0; i < window.parent.document.styleSheets.length; i++){
        currentSheet = window.parent.document.styleSheets[i];
        
        // Loop through CSS rules in each stylesheet
        for(j = 0; j < currentSheet.cssRules.length; j++){

            if (currentSheet.cssRules[j].selectorText != null)
                if (currentSheet.cssRules[j].selectorText.startsWith('.borderShine-'))
                {
                    // Find the Description control and add the border shine class
                    window.parent.document.querySelector("[controlname^='Description']")
                        .classList.add(currentSheet.cssRules[j].selectorText.substring(1));
                    return;
                }
        }
    }
}

Key details about the script:

  • window.parent.document.styleSheets — reaches out of the iframe to the parent page's stylesheets
  • The code searches for a CSS rule whose selector text starts with .borderShine- to dynamically discover the obfuscated class name
  • .substring(1) strips the leading dot from the selector text, since classList.add() expects just the class name
  • The controlname attribute is how BC identifies controls in the DOM, making it possible to target specific fields

Caveats and Limitations

Erik is very upfront that this is a hack and not something you should use in production:

  • The obfuscated class names can change at any time with a BC update
  • Without listening for the animationend event and removing the class, the effect is a one-shot deal — you need to remove and re-add the class to replay it
  • Because BC layers pages, the same control can exist in multiple places in the DOM, meaning the animation might fire on a background instance instead of the visible one

Conclusion

While this border shine hack isn't practical for real-world use, it's a fascinating exploration of how Microsoft implements CSS animations in Business Central. The technique of dynamically discovering obfuscated class names by scanning stylesheets is clever, and the underlying concept of adding CSS animation classes to BC controls opens up interesting possibilities. As Erik suggests, a logical next step would be to create your own custom CSS animation and inject it — which could actually be useful. In the meantime, go poke around in shiny places — you never know what you'll find!