Customizing the look of a Backbase 4 Widget

The widgets (aka "components" or "controls") in the Backbase 4 BTL namespace come in two skins out of the box: system and chameleon. Although that at least gives you some choice, chances are you still want to customize a widget's skin a bit.

This article outlines the various approaches one can take in customizing the look of Backbase 4 widgets, and discusses the pros and cons of each approach. Although it uses BTL widgets as an example, the techniques discussed apply to any Backbase 4 widget.

If you're in a hurry and simply want to know "the best approach", scroll down to the summary and conclusion.

NOTE: this article's focus is only on customizing a widget's visual appearance by changing the CSS that applies to it. Customizing the XHTML structure can quickly become a lot more involved and therefore is not discussed.

Test Scenario

As a test case for each technique discussed below, we will take the following use case: customizing the visual appearance of the BTL Box - probably one of the simplest widgets in the BTL library.

By default, the BTL Box looks like this:

Btl Box

The TDL definition for this widget looks like this (although simplified a bit for the sake of clarity):

<d:element name="box" extends="b:boxBase">
    <d:resource type="text/css">
        .btl-box {
            border: 1px solid #919397;
        }
        .btl-box-inner {
            border: 1px solid #FCFCFD;
            background: #E8EAEC;
        }
    </d:resource>

    <d:template type="application/xhtml+xml">
        <div class="btl-box">
            <div class="btl-box-inner">
                <d:content/>
            </div>
        </div>
    </d:template>
</d:element>

Requirement 1: In the rest of this article, we will discuss techniques to make that box looks like this:

Custom Box

Obviously, this will involve changing the border of the outer "btl-box" div, and the background-color of the inner "btl-box-inner" div.

Requirement 2: the original skin should still be available for other applications, so that an application developer can choose which "look" they want.

Evaluation Criteria

There are several approaches to customizing the CSS for a Backbase widget, and neither of them is necessarily "the best one" - it all depends on your requirements. To help you choose the approach that's right for you, we will evaluate each technique on the following criteria:

  • The CSS skill level that is required to perform the customization
  • The Backbase skill level that is required to perform the customization
  • DRY compliant: does the technique avoid duplicating code (a principle known as DRY principle) in order to still have the original skin available? This is arguably one of the most important criteria, since duplication of code can lead to inconsistencies and maintenance nightmares.
  • Easy upgrade: can the Backbase engine be upgraded without losing customizations to your widgets?
  • Easy packaging: can the modifications to a widget be packaged easily for distribution?
  • Happy co-existence: can the custom-styled widget co-exist with the original styled widget on the same HTML page?
  • Lines of code (count) that need to be changed/added in order to implement the customization

Techniques

1. Edit the original source file(s)

This approach is the easiest one to come up with: you just open up the source file of the BTL Box widget, change some CSS lines and you're done!

<!-- Original BTL Box code, modified -->
...
<d:resource type="text/css">
    .btl-box {
        border: 3px solid #FC6; /* CHANGED */
    }
    .btl-box-inner {
        border: 1px solid #FFF; /* CHANGED */
        background: #FFC; /* CHANGED */
    }
</d:resource>
...

Easy enough, right? Of course, this approach has some very serious downsides:

  • In order to adhere to our last requirement (still having the original skin available), we need to make a copy of the original BTL Box file. This violates the DRY principle.
  • Because we modified the original BTL code, we will have to remember to repeat these modifications when we upgrade to a new Backbase 4 release
  • For each application, we have to decide if we're going to use the original BTL Box file or our custom version (if we load both, one will just overwrite the other). This means we cannot have happy co-existence of a standard box and a custom-skinned box.

2. Put customizations in a global CSS file

Alright, so let's try to leave the original files alone. Of course, we can just specify our own custom CSS rules in our index.html file, either using an style tag in the head or by using an external CSS file:

<!-- index.html -->
<head>
    ...
    <link rel="stylesheet" href="customizations.css" type="text/css" media="screen"/>
</head>

/* customizations.css */
.btl-box {
    border: 3px solid #FC6;
}
.btl-box-inner {
    border: 1px solid #FFF;
    background: #FFC;
}

This approach deals with the violation of DRY and the Backbase upgrade problem, but we still have some issues:

  • CSS specificity: The standard styling is applied through TDL CSS Resource tags. These actually result in new <style> blocks being added dynamically to the head of the HTML page on startup. As a result, your custom CSS rules will actually be overruled by the widget's standard styling, through the rules of CSS selector specificity. You can overcome this by adding "!important" to each custom rule (not very elegant!) or by making your selectors more specific in other ways...
  • The customizations become very fragmented; they are separated from the widget code itself, and if you have customizations for 10 different widgets in one big customizations.css, it will be difficult to distribute just the customized version of your BTL Box.
  • We either include the customizations, or we don't, so we cannot have happy co-existence of a standard box and a custom-skinned box.

3. Extend widget and add new TDL CSS Resource

Of course, global rules are not exactly the True Way of Object Orientationtm. If you want to customize a class definition, you extend it, right?

This is where Backbase 4 really shines compared to Backbase 3: we can easily extend the widget in our own custom namespace and define our custom CSS rules in a new TDL CSS resource:

<d:tdl>
    <d:namespace name="http://www.backbase.com/2008/consulting/tutorials">
        <d:element name="box" extends="b:box">
            <d:resource type="text/css">
                .btl-box {
                    border: 3px solid #FC6;
                }
                .btl-box-inner {
                    border: 1px solid #FFF;
                    background: #FFC;
                }
            </d:resource>
        </d:element>
    </d:namespace>
</d:tdl>

This means we can then use this new widget by using its namespace:

<t:box xmlns:t="http://www.backbase.com/2008/consulting/tutorials">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
    do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</t:box>

This solves the packaging problem, since we now have a perfectly self-contained file containing the customizations for a single widget.

TDL will make sure our custom CSS rules are appended to the head after the standard BTL rules, so CSS specificity is not a problem.

The only downside... we can pretend that we can "scope" CSS rules by placing them in a TDL resource, but reality is that for CSS, there's one global XHTML space. The result of this is that our custom CSS rules now apply to any element with the class name "btl-box". Practically speaking, this means that we still cannot have happy co-existence of the standard BTL Box with our custom BTL Box:

<b:box>
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
    do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</b:box>

<t:box xmlns:t="http://www.backbase.com/2008/consulting/tutorials">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed
    do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</t:box>

The above will simply result in two boxes, both styled in the custom skin.

4. Extend widget and add a CSS class name

So, we're almost there with the previous technique... how can we overcome this last hurdle of co-existence?

The trick is to add a new CSS class name (e.g. "custom-box") to the main view node of our widget:

<d:template type="application/xhtml+xml">
    <div class="btl-box custom-box">
        <div class="btl-box-inner"><d:content/></div>
    </div>
</d:template>

This means we can now very specifically target our custom-boxes with our custom CSS rules, without affecting "standard" BTL Boxes that do not have the "custom-box" CSS class.

Of course, if we were to copy the BTL Box's view template into our custom Box TDL definition, that would again be a violation of DRY...

The final trick to overcome this makes use of little-known fact: templates are internally just "template" methods, and you can therefore call the super element's view template, add just add a CSS class to it.

The final result:

<d:tdl>
    <d:namespace name="http://www.backbase.com/2008/consulting/tutorials">
        <d:element name="box" extends="b:box">
            <d:template type="application/javascript">
                var aElms = bb.callSuper('__template');
                bb.html.addClass(aElms[0], 'custom-box');
                return aElms;
            </d:template>

            <d:resource type="text/css">
                .custom-box {
                    border: 3px solid #FC6;
                }
                .custom-box .btl-box-inner {
                    border: 1px solid #FFF;
                    background: #FFC;
                }
            </d:resource>
        </d:element>
    </d:namespace>
</d:tdl>

Note: this technique still does not support nesting a BTL Box inside you custom box; that requirement would introduce even more complexity.

Summary

For good overview, below is a summary of the various techniques discussed in this article:

1. Edit the original source file(s) 2. Put customizations in a global CSS file 3. Extend widgets and add new TDL CSS Resource 4. Extend widget and add a CSS class name
CSS skill level low high low medium
Backbase skill level low low medium high
DRY compliant
Easy upgrade
Easy packaging
Happy co-existence
Lines of code 3 8 16 22

Conclusion

  • Modifying or copying the original BTL source files is not a good idea;
  • Extending widgets to customize them is considered a best practice;
  • It definitely doesn't hurt to have a thorough understanding of CSS specificity;
  • Technique #4 is guaranteed to work every single time, even with the most complex of widgets, but it does require you know your Backbase and CSS;
  • Technique #3 will most likely be sufficient in 99% of the cases - you only need technique #4 if you need the "happy co-existence" with the original skin within the same Backbase application.
  • In practice, the skinning technique you choose probably depends on your experience in CSS and Backbase