TMS RADical WEB, custom controls using HTML elements


Wednesday, March 14, 2018

In a previous blog, it was demonstrated how custom controls for TMS WEB Core could be created using the FNC framework and how easy it was to use FNC code that was written for VCL, FMX or LCL applications also for web applications.
In this article, we want to cover custom controls from an entirely different angle. That means custom controls that are built from a hierarchy of HTML elements. The example via which we want to explain building such custom controls is about a commonly used UI concept in web development, i.e. a login panel. This is where the user enters his username & password to authenticate. So, in this article, we’ll show the details how to make a TMS WEB Core custom UI control that represents such reusable login panel.

In terms of HTML, the login panel consists of an outer DIV element. In this DIV, we put different DIV elements to hold label text to indicate where the username HTML INPUT element is and where the password HTML input element is. Finally, there is a HTML BUTTON used to confirm the actual entry and do a login.

From a TMS WEB Core custom control perspective, this means we will create a Pascal class descending from TCustomControl and we’ll override the CreateElement virtual method. This CreateElement virtual method is what is responsible for returning the hierarchy of HTML elements representing the UI control. In this case, the code for CreateElement is:

function TLoginPanel.CreateElement: TJSElement;
  br: TJSElement;
  Result := document.createElement('SPAN');
  FCaption := TJSHTMLElement(document.createElement('DIV'));
  FUserInput := TJSHTMLElement(document.createElement('INPUT'));
  FPasswordInput := TJSHTMLElement(document.createElement('INPUT'));
  FUserLabelSpan := TJSHTMLElement(document.createElement('DIV'));
  FPasswordLabelSpan := TJSHTMLElement(document.createElement('DIV'));
  br := document.createElement('BR');
  FButton := TJSHTMLElement(document.createElement('BUTTON'));
  FButton.addEventListener('click', @HandleLoginClick);

Here FCaption, FUserLabelSpan, FUserInput, FPasswordLabelSpan, FPasswordInput and FButton are Pascal references to the HTML elements SPAN, INPUT and BUTTON used in the control. You can see that the HTML elements are created with document.createElement(). This is almost as if one would do this in Javascript, but via the Pascal to Javascript compiler, you can see the DOM object document can be used as Pascal object.

One more note about the CreateElement method, you can see that the purpose of the last line in the method: FButton.addEventListener('click', @HandleLoginClick);
is to attach a TLoginPanel method HandleLoginClick to the HTML element ‘onclick’ event handler. The HandleLoginClick method is declared as

function HandleLoginClick(Event: TJSMouseEvent): Boolean; virtual;

To see how this HTML element event handler is eventually hooked up to trigger the TLoginPanel.OnLogin event, see this code snippet from the TLoginPanel class:

TLoginPanel = class(TCustomControl)
    FOnLogin: TNotifyEvent;
    function HandleLoginClick(Event: TJSMouseEvent): Boolean; virtual;
   procedure DoLogin; virtual;
    property OnLogin: TNotifyEvent read FOnLogin write FOnLogin;

function TLoginPanel.HandleLoginClick(Event: TJSMouseEvent): Boolean;
procedure TLoginPanel.DoLogin;
  if Assigned(OnLogin) then

To interface our Pascal class with the HTML elements two more virtual method overrides are important. There is the UpdateElementVisual method and the UpdateElementData method. The purpose of the UpdateElementVisual method is to do changes to HTML element properties that affect the UI control visually. The UpdateElementData method is to do changes with respect to data contained in the HTML elements.
For this TLoginPanel control, we expose a few properties to set captions for labels in the UI control as well as the values of the HTML INPUT elements for username and password.

The properties of the TLoginPanel used for the login panel data are:

TLoginPanel = class(TCustomControl)
    property CaptionLabel: string read FCaptionLabel write SetCaptionLabel;
    property LoginLabel: string read FLoginLabel write FLoginLabel;
    property Password: string read GetPassword write SetPassword;
    property PasswordLabel: string read FPasswordLabel write SetPasswordLabel;
    property User: string read GetUser write SetUser;
    property UserLabel: string read FUserLabel write SetUserLabel;
The UpdateElementData method is:

procedure TLoginPanel.UpdateElementData;
  FUserLabelSpan.innerHTML := FUserLabel;
  FPasswordLabelSpan.innerHTML := FPasswordLabel;
  FButton.innerHTML := FLoginLabel;
  FCaption.innerHTML := FCaptionLabel;
  (FUserInput as TJSHTMLInputElement).value := FUser;
  (FPasswordInput as TJSHTMLInputElement).value := FPassword;

To customize the look and feel of the login panel, there is a dual approach. The first and classic Pascal like approach is the basic properties are defined to set the background & border color of the panel and the padding and margin of the controls within the panel. The second approach is that the CSS class can be set for the HTML elements used and that also via CSS full customization of look and feel is possible. This leaves the choice to either stick to classical Delphi style RAD development and do all from the form designer or work with separate CSS and perhaps leave the styling to a graphic designer instead of letting the developer do everything.

The visual properties exposed for the TLoginPanel class are:

TLoginPanel = class(TCustomControl)
    property BorderColor: TColor read FBorderColor write SetBorderColor;
    property Color: TColor read FColor write SetColor;
    property ElementClassName: string read FElementClassName write SetElementClassName;
    property ElementCaptionClassName: string read FElementCaptionClassName write SetElementCaptionClassName;
    property ElementInputClassName: string read FElementInputClassName write SetElementInputClassName;
    property ElementButtonClassName: string read FElementButtonClassName write SetElementButtonClassName;
    property ElementLabelClassName: string read FElementLabelClassName write SetElementLabelClassName;
    property Margin: integer read FMargin write SetMargin;
    property Padding: integer read FPadding write SetPadding;

The Element*ClassName properties allow to set CSS class names for the control itself (outer DIV), the SPAN elements for the labels associated with the INPUT elements and of course of also for the HTML INPUT and BUTTON elements.

The UpdateElementVisual override becomes:
procedure TLoginPanel.UpdateElementVisual;
  strpadding,strmargin: string;
  if Assigned(ElementHandle) then
    strpadding := IntToStr(Padding)+'px';
    strmargin := IntToStr(Margin)+'px';
    if (ElementClassName = '') then
    begin'background-Color',ColorToHTML(Color));'border', 'solid 1px '+ColorToHTML(BorderColor));'padding',strPadding);
    if (ElementCaptionClassName = '') then
    if (ElementInputClassName = '') then
    if (ElementLabelClassName = '') then
    if (ElementButtonClassname = '') then

Notice how the properties are set when no CSS class is specified for HTML elements or otherwise the look and feel will be determined by the CSS.

The result becomes:

This is the basic look and feel without CSS.

Now, let’s bring bootstrap CSS and some custom CSS in the game and see the new look and feel.

Bootstrap is introduced with adding

<link rel="stylesheet" href="">

to the project HTML file and in addition we add CSS in the project HTML file <STYLE> section to control the LoginPanel look & feel:
    .labelcenter {
      text-align: center;
    .loginpanel {
      padding: 15px;
    .loginpanelelement {
      margin-top: 2px;
      margin-bottom: 2px;
Now the appearance of the panel becomes:

We have only scratched the surface here of the many possibilities to enrich the TMS WEB Core framework with custom UI controls but we hope we have generated interest and enthusiasm.

Get started today: Technical previews of TMS WEB Core, TMS FNC UI web-enabled controls, web-enabled TMS XData, the first parts under the TMS RADical WEB umbrella are exclusively available now for all active TMS-ALL-ACCESS customers.

Bruno Fierens


This blog post has received 3 comments.

1. Wednesday, March 14, 2018 at 1:17:11 PM

Wow! The possibilities...!!!!

Bosnjak Boris

2. Thursday, March 15, 2018 at 12:50:30 AM

The method UpdateElementVisual seems a little messy to me. Do you think there could be a cleaner way to implemenent that?

Bracey Mark

3. Thursday, March 15, 2018 at 8:24:13 AM

The UI control is made up of 6 underlying HTML elements that can potentially be controlled here. So, code for this is needed, unless you decide to always control everything to CSS, then you''d not need to add this code. I''m not sure what ''cleaner way'' you are hinting at otherwise.

Bruno Fierens

Add a new comment:
  You will receive a confirmation mail with a link to validate your comment, so please use a valid email address.
Change Image
Fill in the characters from the image above:

All fields are required.

Previous  |  Next  |  Index