/ Development  

Revolutionize layouts with this simple trick adding a custom icon to a tab

Hi there AppWorks fans,

Welcome to a new installment of AppWorks tips.

A simple feature explained on this week of this new year, but it can be a challenging task when you don’t know where to start looking. What am I talking about? Well, have you ever wondered why you don’t see any nice icons when you stack panels on top of each other (to get tabs) in a layout? I don’t have a clue why that is!? Only, our end-users like to have a fancy User-Xperience and this falls, or stands with proper icons, coloring, and logically placed elements. Long, long time ago we already played with a ‘Theme’ type of document with CSS (or better LESS) in this post. I use my own post as start point for this post…

Let get right into it…

We directly dive into our workspace/project where we have a simple ‘Project’ entity available with just one prj_name property; As great low-code developer you updated all the generated BBs nicely with your own naming standards and saved the entity in a folder with name entities. With this prototype ready, create an instance in runtime and open/view it with the default generated layout.


To make this view a bit nicer, we can add an icon to our form! Open the layout lyt_default of the entity and update the setting of the form panel. Simple and efficient like this:


Don’t ask me why it’s called ‘Chrome’ as this option also works in ‘Edge’!

The end-result?


Now, move back to that lyt_default layout in the designer and stack a second form panel onto the current form. This makes a tab-panel in your layout. You will that see the ‘Full-Chrome’ option grayed out on both tabs. This is the view after a publication:


WHAT? Where are my nice end-user icons? Yes, that’s what we would like to solve in this post!

The solvation-part

Let’s do one step back…Remove the tabbed form (from the layout), republish again, and check the icon element from the “Developer tools” <F12> perspective:


For some strange reason I first needed to remove both forms from the layout and add a new one to reconstruct the icon in runtime…It is what it is!

This is the HTML-snipped loading an SVG image:

<panel-header class="emp-panel-header au-target" ref="panelHeader" au-target-id="1167" style="display: block;">
<div class="panel-header-child">
<div show.bind="panel.usage.chrome ===&quot;full&quot;" class="panel-icon au-target" au-target-id="1168">
<img src.bind="panelImage" class="panel-icon-img au-target" bs-tooltip="" au-target-id="1169" alt="Layout panel icon" src="data:image/svg+xml;charset=utf-8,%3Csvg width='32' height='32' viewBox='0 0 32 32' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M16 31.973C24.8216 31.973 31.973 24.8216 31.973 16C31.973 7.17835 24.8216 0.0269928 16 0.0269928C7.17835 0.0269928 0.0269928 7.17835 0.0269928 16C0.0269928 24.8216 7.17835 31.973 16 31.973Z' fill='white'/%3E%3Cpath d='M16 30.939C24.2506 30.939 30.939 24.2506 30.939 16C30.939 7.74941 24.2506 1.06099 16 1.06099C7.74941 1.06099 1.06099 7.74941 1.06099 16C1.06099 24.2506 7.74941 30.939 16 30.939Z' fill='%232E3D98'/%3E%3Cpath d='M18 7V11C18 11.2652 18.1054 11.5196 18.2929 11.7071C18.4804 11.8946 18.7348 12 19 12H23' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M21 25H11C10.4696 25 9.96086 24.7893 9.58579 24.4142C9.21071 24.0391 9 23.5304 9 23V9C9 8.46957 9.21071 7.96086 9.58579 7.58579C9.96086 7.21071 10.4696 7 11 7H18L23 12V23C23 23.5304 22.7893 24.0391 22.4142 24.4142C22.0391 24.7893 21.5304 25 21 25Z' stroke='white' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M17.5168 14.9649C17.8124 14.9649 18.0519 15.2045 18.0519 15.5C18.0519 15.7955 17.8124 16.0351 17.5168 16.0351H12.4832C12.1876 16.0351 11.9481 15.7955 11.9481 15.5C11.9481 15.2045 12.1876 14.9649 12.4832 14.9649H17.5168ZM19 15C19 14.4477 18.5523 14 18 14H12C11.4477 14 11 14.4477 11 15V16C11 16.5523 11.4477 17 12 17H18C18.5523 17 19 16.5523 19 16V15Z' fill='white'/%3E%3Cpath d='M17.5168 20.9649C17.8124 20.9649 18.0519 21.2045 18.0519 21.5C18.0519 21.7955 17.8124 22.0351 17.5168 22.0351H12.4832C12.1876 22.0351 11.9481 21.7955 11.9481 21.5C11.9481 21.2045 12.1876 20.9649 12.4832 20.9649H17.5168ZM19 21C19 20.4477 18.5523 20 18 20H12C11.4477 20 11 20.4477 11 21V22C11 22.5523 11.4477 23 12 23H18C18.5523 23 19 22.5523 19 22V21Z' fill='white'/%3E%3Cpath d='M14.5 12H11.5C11.2239 12 11 12.2239 11 12.5C11 12.7761 11.2239 13 11.5 13H14.5C14.7761 13 15 12.7761 15 12.5C15 12.2239 14.7761 12 14.5 12Z' fill='white'/%3E%3Cpath d='M14.5 18H11.5C11.2239 18 11 18.2239 11 18.5C11 18.7761 11.2239 19 11.5 19H14.5C14.7761 19 15 18.7761 15 18.5C15 18.2239 14.7761 18 14.5 18Z' fill='white'/%3E%3C/svg%3E%0A" data-original-title="" title=""><!--anchor-->
<label class="panel-label au-target" bs-tooltip="" tabindex="0" au-target-id="1171" for="panel-name-Form" data-original-title="" title="">Form</label><!--anchor--> <input type="text" style="display:none" class="au-target" au-target-id="1174" id="panel-name-Form">
<div ref="settingsMenu" style="white-space:nowrap" class="au-target dropdown panelMenuForm" au-target-id="1175">
<bs-image-button escape-key-down-event-name="escape-key-down-event" escape-key-down-event.delegate="removeFocusOnEscape($event)" ref="panelExpander" prop.one-time="ctrl1" class="panel-maximize expandPanel expand-panel au-target" click-event-name="expand-panel-click" expand-panel-click.delegate="expandPanel($event, panelParentContainer, panelContainer)" enter-key-down-event-name="expand-panel-key-down" expand-panel-key-down.delegate="expandPanel($event, panelParentContainer, panelContainer)" au-target-id="1178" awlc-client-id="d347b44cad53c5c4f685f777c718c23"><button class="btn au-target" disabled.bind="disabled" type="submit" ref="button" bs-tooltip="" keydown.delegate="keyDown($event)" tabindex.bind="tabindex" click.delegate="click($event)" blur.trigger="blur($event)" au-target-id="75" aria-label="Maximize" tabindex="0" data-original-title="" title=""><img class="au-target" au-target-id="76" src="" alt="Maximize"></button></bs-image-button>

Now, return to the stacked form option again, do a publication, and check the tab in runtime via the developer tools. The tab icons are gone, but let’s CSS-hack the icons back into place by adding a style rule:


A little CSS background on label#tab-header-0

  • label is the HTML-element
  • #tab-header-0 is the id attribute in the html element; A CSS-selector on ID-value!
  • You can also do a CSS-selector on CLASS-value: label.nav-label; Watch the difference in #/.
  • Get more specific with a CSS-selector on attribute-value: label.nav-label[title="Form"]

With this commented knowledge in mind, we can easily produce something like this:

label.nav-label[title="Form"] {
background: url("") no-repeat left;
padding-left: 25px;
background-size: 20px;

Now you guess what should be place between those quotation marks for the url("")!? to have a result like this:


It’s a party! 🎉

The answer to that question is off course the value of that src attribute of our HTML snipped from above. This value starts with data:image/svg+xml;....

The “advanced” theme document

All nice and great what we did in the previous section, but this is not a solid solution! After a refresh of the page, our changes are gone. So, how to use this CSS part nicely in our solution? Well, that will be our document of type ‘Theme’…Aha! I already referred to it in the intro of this post…

I have a theme document with thm_default in the theme folder of my solution. Open it and jump to the ‘Advanced’ tab. You see some CSS variable definitions starting with @ (This is a LESS feature) and after this you will see the body{} CSS part. Scroll all the way down (to the end) and add your own CSS part outside the body-part. Save it and publish it; this will result in a custom.css behind URL:

Have a refresh in runtime and check the result. Use an incognito tab if you don’t see the result directly!


For those innovative people

We now reused the data:image/svg+xml;... string for our image, but how about the popular icons from fontawesome? You can download the SVG file, save it in an ‘assets’ folder of the project, and publish it into runtime via a document of type ‘Web Library Definition’; Have a read about WLD here. You’re CSS part will look like this:

label.nav-label[title="Form"] {
background: url('/home/appworks_tips/nl-bos-gen-assets/images/umbrella-beach-solid.svg') no-repeat left;
padding-left: 25px;
background-size: 20px;

Don’t want SVG? Convert the SVG to PNG on svgtopng.com.

Ohw yeah! That’s a nice iconized “DONE”. We again see what a little CSS powder can do for our end-users. It’s a small thing but trust me this will improve UX overall for the AppWorks runtime. There is nothing more to tell, just try out these kinds of small tweaks yourself and validate the benefits before you dive into a full-blown custom UI on itself with all the fancy JavaScript frameworks these days. Stay with your roots and pick the fruits of simplicity! Have a great weekend…cheers.

Don’t forget to subscribe to get updates on the activities happening on this site. Have you noticed the quiz where you find out if you are also “The AppWorks guy”?