Using CSS in Qlik Sense

Whether you are building extentions in Qlik Sense or including Qlik Sense objects in a mashup you very likely will need some CSS. There are even some things you can really only do with CSS. And since Qlik released Themes support there is also the possibility of adding your own stylesheets to the Qlik Sense client with or without other changes, like extensions or mashups.

But stylesheets are different. They are not like javascript, with a defined API with methods, parameters and return values. Instead they have their own logic, with CSS selectors, specificity and interdependance. When something breaks, you won’t get error messages but things will just look wrong, not be visible at all or stop working. And very little is documented.

The qv-object rule

When you build an extension you can include CSS rules. To make it possible for you to add rules that affect only your extension Qlik Sense will add a CSS class with the format ‘qv-object-[extension]’ to the HTML element your extension is rendered in. So if your extensions qext filename is xxxx.qext, it will add the CSS class ‘qv-object-xxxx’. The idea is that you should prefix all your CSS rules with qv-object-xxx, somthing like this:

.qv-object-xxx .qv-object-content {
  overflow: auto;
}

.qv-object-xxxx ul {
  list-style: none;
}

.qv-object-xxxx .important {
  color: red;
}

If you don’t do this, your styling might affect other content in the page. Sometimes that is what you want, but for normal extensions you should not do that. You might break other stuff in the page and create bugs that are hard to find.

Extension HTML structure

The structure your extension is rendered into looks like this(this is a simplified structure):

<article class="qv-object qv-object-xxx">
  <div class="qv-inner-object">
    <header class="qv-object-header">
      <h1 class="qv-object-title">
        <h2 class="qv-object-subtitle"></h2>
      </h1>
    </header>
  </div>
  <div class="qv-object-content-container">
    <div class="qv-object-content">
      Your extension renders here
    </div>
  </div>
</article>

This means that:

  • a .qv-object-xxxx rule will affect the whole box the extension is rendered in, including title
  • a .qv-object-xxxx .qv-object-content rule will affect just the extension body, not titles etc
  • a .qv-object-xxxx .qv-object-title will affect the title and possibly the subtitle
  • hoover buttons are outside of the qv-object-xxxx element and cannot be styled based on the qv-object-xxxx class

Note that this structure is as far as I know undocumented. It has been pretty stable so far, but still might change in the future. The same structure is used for both built-in and extensions, might be good to know if you are building a mashup.

Loading your CSS

To make your CSS rules work you need to load them in the browser. They should be loaded once, even if your extension is used several times in the same page/sheet. The best place to do this is at the very start of your code, at the beginning of the callback function in the define call.

There are two ways of loading the CSS. First you could add a link to the CSS file to the HTML page. An easy way to do this is with the requirejs css plugin, like this:

define( [ "css!./style.css"], function () {
/* requirejs will add a link to the document, nothing more is needed */

You could do this yourself too, but there is really no reason to do this, and you need to be careful and handle all cases, like virtual proxies and when your extension is used in a mashup not served by Qlik Sense.

The other possibility is to add the contents of your stylesheet to a style element in the document header. That requires a bit more code:

define( ['jquery', 'text!./style.css'], function ($, cssContent ) {
    $( '<style>' ).html(cssContent).appendTo( 'head' );

You can also do it without using jQuery, with standard javascript, but that means a few more lines.

The first method, adding a link to the stylesheet, has the advantage that references to external resources, like images and fonts, works, provided that you include those files in your extension too. But if you are running the extension in a mashup on an external (not Qlik Sense) server you might run into problems, since there are security restrictions on loading CSS from other servers.

That’s why I generally use the second method, adding the stylesheet text to the document. Images referenced in the stylesheet then needs to be Base64-encoded and included in the stylesheet itself. That works well for small images, if they are not too many. But if you have many images, or need to load for example font files, you should probably go for the link method.