Designing a Simple Polymer Web Component: Part 2 – Styling

In my previous post I created the foundation of my web component but it didn’t look how I wanted it to. Today I am going to finish off the web component visuals. Most of my work was with playing with the CSS. However, I bumped into some roadblocks that are worth highlighting.

Styling the content blocks

My initial CSS just had an embedded img and h1 selector. This is the wrong way to be selecting the stuff inside content and the Polymer documentation is quite explicit about it. Surroung the <content> block with a div that has a selector, then use a recipe. My characterName section became this:

.characterName {
    position: absolute;
    top: 70%;
    left: 0;
    width: 100%;
    height: 30%;
    text-align: center;
    vertical-align: middle;
    background-color: beige;

    &gt; ::content h1 {
        font-family: 'Segoe Script', cursive;
        margin: 2% 0 !important;

Note the ::content – this is the selector nomenclature for the content block. I did something similar to the img tag as well so that it always fit within the characterImage content block.

Bootstrap, DOMReady and Scripts

One of the things I wanted to do was to make the element square. The work is a simple one-liner in Javascript: = elem.offsetWidth + "px";

Placing it at the right point in the code is critical. My first attempt did it in the scripts section of Index.cshtml with jQuery, like this:

$(document).ready(function () {
    $("dnd-gridcharacter").each(function (idx, elem) {
        $(elem).css({ height: $(elem).outerWidth() + "px" });

This does not hit the encapsulation requirement I had set for myself. My component should not have to rely on external scripts in order for it to work properly. I also had a problem with resizing. If the external app resized my element, then the element should resize accordingly to keep the square shape. Setting the height once was not enough.

After some trial and error, I ended up with the following code in my dnd-gridcharacter.js file:

    //#region Global Event Listeners
    domReady: function() {

    windowResize: function() { = this.offsetWidth + "px";

    //#region Lifecycle event handlers
    ready: function() {
        console.log("dnd-gridcharacter::ready: %s %s", this.localName,;

        var that = this;
        // Add event handler for DOMContentLoaded
        if (document.readyState != 'loading') {
        } else {
            window.addEventListener('DOMContentLoaded', function () { that.domReady(); });

        // Add event handler for window resize
        window.addEventListener("resize", function() { that.windowResize(); });

This code does not work by itself. Let me go through it first. I have two methods in the object that will be called when the page DOM is ready and when the window gets resized. To implement those, I add an event listener on the DOMContentLoaded event in the ready() method. ready() is a Polymer event that fires once the element has been created and had the shadow DOM fully populated.

So why didn’t it work? When I ran my page the size of the element was not set. I added a console.debug to print the this.offsetWidth to verify this. It was as if styling had not been rendered yet. Was I capturing the right event?

I tend to wander the Internet when this happens. In this case I went to the Mozilla Developer Network and started researching events. I started reading the description for the DOMContentLoaded event to ensure that I was indeed using the right event. At the top of the page is this warning:


The implication is less than clear here. If you don’t have a script at the bottom of your page, then the DOMContentLoaded event is fired early – before the page is fully rendered out. The DOM is there but not the styling. I wanted details of the styling.

The way to fix this is to include a script at the bottom of the main page. I wanted to bring in Bootstrap and their grid component anyway. Bootstrap has a dependency on jQuery. Use jspm install bootstrap to bring in the library and include it in the Layout.cshtml file:

<!DOCTYPE html>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="~/jspm_packages/npm/font-awesome@4.3.0/css/font-awesome.min.css" rel="stylesheet">
    <link href="~/jspm_packages/github/twbs/bootstrap@3.3.4/css/bootstrap.min.css" rel="stylesheet">

    <!-- Required Polyfills -->
    <script src="~/jspm_packages/npm/webcomponents.js@0.6.0/webcomponents-lite.min.js"></script>

    <!-- Components used -->
    @RenderSection("htmlelements", required: false)

    <div class="flex-container">

    <!-- Requirement for BootStrap -->
    <script src="~/jspm_packages/github/components/jquery@2.1.3/jquery.min.js"></script>
    <script src="~/jspm_packages/github/twbs/bootstrap@3.3.4/js/bootstrap.min.js"></script>

    <!-- Page Scripts -->
    @RenderSection("scripts", required: false)

Relative Font Size

Another task that took me a while to figure out was the sizing of the character name. The dnd-gridcharacter element can be any height, so I had to account for the size differences. A quick search on Stack Overflow brought up eight questions that fit my criteria, each – of course – with a slightly different variation. I went for the simplest, which is to calculate the font size. To do this, I used the following code in the resizeWindow() method of my dnd-gridcharacter.js file:

    windowResize: function() {
        // Make the object square by setting height == width = this.offsetWidth + "px";

        // Make the character name font fit inside the containing DIV
        var textHeight = Math.floor(this.offsetHeight * 0.12);
        Polymer.dom(this).querySelector("h1").style.fontSize = textHeight + "px";

You may be wondering why 0.12 as the multiplier? The character name section is 30% of the overall component height. I want to allow for some padding around the text (around 2% of the room), which brought it to 26% of the overall component height. I wanted to allow for two lines, like in my example, which brough it to 13%. When I looked at the result, I decided that the line height may be a little different than the font size, so I reduced it just a little more. It’s not very scientific but the result looks good.

A quick note about the Polymer.dom call. Polymer needs to deal with the Shadow DOM and, for those browsers without Shadow DOM, a fake version that they call “Shady DOM”. The Polymer.dom() abstracts the difference away from you, so it works in whatever browser you need. It has a restricted subset of functions for finding and manipulating the DOM – I’m sure that will be expanded over time so that you can do anything in the Polymer.dom() API that you can in the regular DOM API. There are some caveats with using Polymer.dom() to manipulate the DOM, so make sure you read the documentation first.

Icons and Observers

The last thing I needed to do was to implement the icons. I’ve got my icons from the Windows 8 Metro Invert Iconset. This set is large and has all sorts of things. I’m not sure I’ll stick with it. I’ve downloaded two icons – one for sharing and one for groups. Both icons are PNG format and 128x128px. I added them into my dnd-gridcharacter.html file like this:

<dom-module id="dnd-gridcharacter">
    <link rel="stylesheet" href="dnd-gridcharacter.css">
        <div class="content-wrapper">
            <div id="partyIcon"><img src="/style/icons/group.png"></div>
            <div id="shareIcon"><img src="/style/icons/share.png"></div>
            <div class="characterPicture"><content select="img"></content></div>
            <div class="characterName"><content select="h1"></content></div>

<script src="dnd-gridcharacter.js"></script>

Note that I have changed the class to an ID for the partyIcon and shareIcon DIVs. This is because I want to reference them in code explicitly. I’ve also changed the CSS to match this change. I have not wired the logic up at this point, and I had to add a little bit of CSS to get the icons to be resized and the right size.

I want to ensure that the party and share icons only appear by default when those attributes are set. To do this, I’ve added a couple of famous characters to my grid in Index.cshtml:

@{ ViewBag.Title = "Home Page"; }

<h1>Home Controller</h1>

<div class="container-fluid">
    <div class="row">
        <div class="col-lg-2 col-md-2 col-sm-4 col-sx-12">
            <dnd-gridcharacter party shared>
                <img src="/style/avatars/gnome/wizard.jpg">
        <div class="col-lg-2 col-md-2 col-sm-4 col-sx-12">
            <dnd-gridcharacter party>
                <img src="/style/avatars/personal/elminster.png">
        <div class="col-lg-2 col-md-2 col-sm-4 col-sx-12">
            <dnd-gridcharacter shared>
                <img src="/style/avatars/personal/drizzt.jpg">

@section htmlelements {
    <link rel="import" href="/jspm_packages/github/Polymer/polymer@0.8.0/dist/polymer.html">
    <link rel="import" href="~/elements/dnd-gridcharacter.html">

I’ve downloaded some different images to represent them. Elminster should have the party icon but not the shared icon and Drizzt should have the share icon but not the group icon.

Right now, I don’t know when, or indeed IF, the observers are called. To determine this, I put a console.log statement to find out:


Based on the console, the observers are called before the element is “ready” even on element creation, so I don’t have to do any work in the ready() method. The observer just needs to change the display property based on whether the newValue is true or not, like this:

    //#region Property Observers
    partyObserver: function (newValue, oldValue) {
        this.$ = newValue ? "block" : "none";

    sharedObserver: function (newValue, oldValue) {
        this.$ = newValue ? "block" : "none";

Note the use of this.$ – this is a collection of the elements with IDs in my component and I can use this to easily identity the various blocks in my shadow DOM.

The Final Result

The final result looks like this on screen:


This is pretty much what I envisioned when I first created the powerpoint version (for reference – I’ve shown it again below):


The difference is that I’ve done all the code and the component is fully responsive to changes in sizes and can be instantiated as many times as I want. I may need to do more to implement other items in my application, but this is looking good now.

This is probably a baseline web component for me. It isn’t the very basic version that I implemented in the polymer-helloworld component, but it doesn’t have a lot of bells and whistles either. As a result, I’ll be able to use this as a model going forward.

Got an idea on how to improve my web component? Let me know in the comments.

I’ve checked in my work on this web component using tag cs-0.0.4.