Qlik Sense / Qlik Analytics Platform Articles, Projects & Tutorials by Stefan Walther

Chapter 03 - Let's Get Started: Hello World Example

The first example is extremely easy, let’s just create a simple „Hello World“ visualization extension. In the following chapters we’ll improve this example and extend it with additional functionality.

So what’s necessary to create a Qlik Sense Extension? Let’s first have a look at the anatomy of an extension:

The anatomy of a Qlik Sense extension

The following files are mandatory when creating a Qlik Sense Extension:

  • Main script file
  • Extension meta data file (.qext)

In addition to the mandatory files an extension project may certainly have one or more of the following complementary file-types:

  • External scripts
  • Style sheets (.css files)
  • Images, icons and fonts
  • and other resources ...

Skeleton of a script file

This is the basic skeleton of a script file for a visualization extension for Qlik Sense:

define( [ /* dependencies */ ],
    function ( /* returned dependencies as arguments */ ) {
        'use strict';
        return {

            // Paint resp.Rendering logic
            paint: function ( $element, layout ) {
                // Your rendering code goes here ...                
    } );


define is a concept introduced by RequireJS to define dependencies in your JavaScript files. The idea is to load external dependencies before your main script gets executed (read more here).
In our example above we do not load any dependencies, but we'll do in further chapters of this tutorial.


paint is the main method to render the visualization.

It will be called every time the visualization should be rendered, either because of new data from the server or because it has been re-sized.

The paint method receives two parameters, $element and layout.

$elementjQuery wrapper containing the HTML element where the visualization should be rendered.
layoutData and properties for the visualization.

Structure of the .qext file

The basic structure of a .qext file looks as follows:

    "name" : "Extension Tutorial - Hello World",
    "description" : "Extension Tutorial, Chapter 3, Simple Hello World.",
    "icon" : "extension",
    "type" : "visualization",
    "version": "0.1",
    "preview" : "bar",
    "author": "Stefan Walther"


When creating your .qext file you should double-check if this file meets the requirements of a valid .json file.


The property name will be re-used in the list of visualizations and the preview:


The description is visible in the preview:


The following values are possible for setting the icon:

  • bar-chart-vertical
  • combo-chart
  • extension
  • filterpane
  • gauge-chart
  • kpi
  • line-chart
  • list
  • map
  • pie-chart
  • pivot-table
  • scatter-chart
  • table
  • text-image
  • treemap

You can find more about the icon property in the official documentation.


Defines the type of the extension, should be always visualization as of now.


Define the version of your visualization extension, I recommend to use Semantic Versioning.


Qlik Sense for Developers states:

You can define a custom preview image that is visible when the visualization has been deployed to Qlik Sense. The preview image is visible when selecting the visualization in the Library or Assets panel. This is done by defining the preview parameter in the qext file.
If you do not define the preview parameter in the qext file, the icon definition will be used for rendering the preview image as well.


If you want to create a preview image, choose width and height of 140px x 123px.


author references the author of the visualization extension, so probably your name.
Note, as of this is not visible in neither the Qlik Sense Desktop nor Qlik Sense Server, so you can only get information about the author if you open the .qext file.

Creating the Hello World example

Considering the anatomy of a Qlik Sense Visualization Extension we can now create our "Hello World" example as follows:

Create the Container

The easiest way to get started is to use Qlik Sense Desktop and create a folder containing the two required assets where Qlik Sense Desktop is loading extensions from.

So let's create folder called "Extension Tutorial - Hello World" under


Create a .qext file

Then create a exttut-03-helloworld.qext file and paste the following code into it:

    "name" : "Extension Tutorial - Hello World",
    "description" : "Extension Tutorial, Chapter 3, Simple Hello World.",
    "icon" : "extension",
    "type" : "visualization",
    "version": "0.1",
    "preview" : "bar",
    "author": "Your Name"

The Script File

Then add the following script to a file called exttut-03-helloworld.js:

define( [
    function ( $ ) {
        'use strict';

        return {

            //Paint resp.Rendering logic
            paint: function ( $element, layout ) {

                var $helloWorld = $( document.createElement( 'div' ) );
                $helloWorld.html( 'Hello World from the extension "01-ExtTut-HelloWorld"<br/>' );
                $element.append( $helloWorld );

    } ); 

Test It

Before we dig into details what this code does, let's just test it.
Just follow these steps:

  1. Open Qlik Sense Desktop
  2. Open an existing app or create a new one
  3. Open an existing sheet or create a new one
  4. Go to Edit mode and then you should see the extension "Extension Tutorial - Hello World"
  5. Drag and Drop it onto the sheet and exit the Edit mode

You should see something like that:


If this is the first time that you are working with Qlik Sense (Desktop) I've added a step by step guide to the appendix which will guide you trough creating your first app and testing this extension.

But wait, something went wrong

Before jumping to the next chapter you'll probably realize that there is something wrong with our solution.
As soon as you resize the (browser-)window you'll recognize that our output get multiplied, so you'll end up into something like that:

So why did this happen?
The answer is quite easy. Have a look above to the description of the paint. This method will always be called when the visualization should be rendered, and a resize triggers the paint.
So in fact we are appending a new $helloWorld object to $element on every resize.

There are several ways how to solve this, I'll introduce two of them:

1) Be lazy, just remove existing content

You can remove all child nodes of $element at the beginning for your paint method (by using the jQuery empty() method).

Just add the following line at the beginning of paint


2) Be smarter, detect if the your new node already exists

var id = layout.qInfo.qId + '_helloworld';
var $helloWorld = $( '#' + id );
if ( !$helloWorld.length ) {
    console.log( 'No element found with the given Id, so create the element' );
    $helloWorld = $( document.createElement( 'div' ) );
    $helloWorld.attr( 'id', id );
    $helloWorld.html( 'Hello World' );
    $element.append( $helloWorld );
} else {
    console.log( 'Found an element with the given Id, so just change it' );
    $helloWorld.html( 'Hello World' );

Reviewing this example you'll also recognize something new, the usage of the layout object to get the unique Id of the current object (too prevent conflicts if you are using the same object several times on a sheet). We'll talk more about layout in upcoming chapters.

Performance Impact ?
Scared about the performance impact of the first approach? I was too, so I did some basic tests:

I leave it to you whether you decide to go with better performance or better readability of your code ...

To improve readability of code examples in this tutorial I'll in general stick to the empty() pattern.