Customizing your Qlik Sense apps not only enhances their visual appeal but also ensures consistency with your organization's branding guidelines. With custom themes you can modify colors, fonts, and layouts on both global and granular levels, giving you complete control over the look and feel of your analytics.
In this blog post, we'll dive into the essentials of building a custom theme, dissect the anatomy of the theme's JSON file, and share some tips and tricks to help you create themes easily.Bonus: along the way, we will be creating a Netflix inspired theme. We'll go from this:to this:Getting Started:The Essentials of Building a Theme
A custom theme in Qlik Sense is a collection of files stored in a folder.
It typically includes:
Definition File (.qext): This file defines the theme's metadata, such as its name, description, type, and version.{
"name": "Netflix Theme",
"description": "A custom theme inspired by Netflix's branding.",
"type": "theme",
"version": "1.0.0",
"author": "Ouadie Limouni"
}
Main JSON File (.json):The core of your theme where you define styles, colors, fonts, and other visual properties.
Optional Assets:
CSS Files: For additional styling that can't be achieved through the JSON file alone.
Font Files:Custom fonts to enhance typography.
Images: Logos or background images to incorporate into your theme.
Folder structure example:
netflix-theme/
├── netflix-theme.qext
├── theme.json
├── netflix.css (optional)
├── BebasNeue-Regular.ttf (optional)
└── images/ (optional)
└── background.jpg
Anatomy of the `theme.json` File(The full theme code is attached at the end of this blog post)
Variables Section (_variables)
Variables allow you to define reusable values (like colors and font sizes) that can be referenced throughout your theme. Variables must be prefixed with `@`.Example:
"_variables": {
"@primaryColor": "#E50914",
"@backgroundColor": "#141414",
"@ObjectBackgroundColor": "#3A3A3A",
"@fontColor": "#FFFFFF",
"@secondaryColor": "#B81D24",
"@fontFamily": "\"Bebas Neue\", Arial, sans-serif",
"@fontSize": "14px"
}
Global Properties
These properties set the default styles for your entire app.
Color: Sets the default font color.
Font Size: Sets the default font size.
Font Family: Sets the default font family.
Background Color: Sets the default background color for visualizations.
Sheet Styling
Customize the appearance of sheets, including the title backgrounds.
Object Styling
Control the styling of various objects (charts, tables, etc.) in your app.
Data Colors
Define how data appears in your visualizations, including primary data color, colors for null values, and colors for different selection states.Learn more here.
Palettes and Scales
Palettes are arrays of colors used for dimensions (categorical data). You can define custom palettes for data and UI elements.
"palettes": {
"data": [
{
"name": "Netflix Data Palette",
"scale": [
"#E50914",
"#B81D24",
"#221F1F",
"#FFFFFF"
]
}
],
"ui": [
{
"name": "Netflix UI Palette",
"colors": [
"#FFFFFF",
"#B3B3B3",
"#333333",
"#000000"
]
}
]
},
Scales are used for measures (numerical data) and can be gradients or classes.
"scales": [
{
"name": "Netflix Red Gradient",
"type": "gradient",
"scale": ["#B81D24", "#E50914"]
},
{
"name": "Netflix Grey Gradient",
"type": "gradient",
"scale": ["#333333", "#B3B3B3"]
}
],
Custom Fonts and StylesTo achieve the Netflix-style typography, we can use a font similar to Netflix's branding. For this example, we'll use "Bebas Neue", a free font that's close in style.
Extended Object Styling
You can apply specific styles to individual chart types, overriding global settings.
Example for a Bar Chart:
"barChart": {
"label": {
"value": {
"color": "@fontColor",
"fontSize": "12px",
"fontFamily": "@fontFamily"
}
},
"bar": {
"fill": "@primaryColor"
},
"outOfRange": {
"color": "#404040"
}
},
Tips and Tricks
Creating custom themes can be a rewarding experience, and here are some tips to help you along the way:
1. Use Variables for Consistency
Defining colors, font sizes, and other reusable values as variables ensures consistency across your theme and makes updates easier.
"_variables": {
"@primaryColor": "#E50914",
"@fontSize": "14px"
}
2. Leverage Inheritance
The `_inherit` property allows your theme to inherit properties from the default theme, reducing the amount of code you need to write.
{
"_inherit": true,
// Your custom properties here
}
3. Test Incrementally
Apply your theme during development and test changes incrementally. This approach helps you catch errors early and see the immediate impact of your changes.
4. Organize Your Theme File
Keep your `theme.json` file organized by grouping related properties. This practice makes it easier to navigate and maintain your theme.
5. Prefix Your Variables and Themes
To avoid conflicts with other themes or variables, use unique prefixes.
"_variables": {
"@netflix-primaryColor": "#E50914",
}
6. Validate Your JSON Files
Always validate your JSON files to prevent syntax errors. Use online tools like JSONLint.
7. Utilize Custom Fonts Carefully
Don't overuse custom fonts and ensure that any custom fonts you use are properly licensed for use in your application.
8. Use High-Quality Images
If you're incorporating images (like backgrounds or logos), make sure they are high-quality and optimized for web use.
-> Stay up-to-date with the latest on qlik.dev
Applying the Netflix Theme to Your App
Once you've created your custom theme, you can apply it to your Qlik Sense app:
1. Upload the Theme: Upload the zipped folder to the Themes section in your Console.2. Apply the Theme: In your app, go to the App options menu, select Appearance, and choose your custom theme from the list.
📌 If you are an advanced developer, checkout the following blog posts that tackle theming in an embedded context:- Theming with Picasso.js- Qlik Embed (theming section towards the end)
Happy theming!
...View More
A new file management system has been added to Qlik Cloud allowing users to create folders and subfolders for their data files. This hierarchical folder structure is available in your personal space, as well as shared, managed and data spaces. Now, I can add folders to a data space in my tenant and use folders to organize my files. This is extremely helpful when I have a project that has a lot of data files.
There are two ways to add folders to a space. The first is through Space details as seen in the image below.
After clicking on Space details, select Details. Then select Data files.
From the screenshot below, I can use the icons at the top or click on the eclipse at the end of a folder row to:
Upload files to a folder
Add a folder
Copy a folder
Cut and paste a folder
Delete a folder
I can also use the icons and menu options to cut, copy and paste files and/or folders to somewhere else within the space or to another space. More than one file can be cut/copy/pasted by selecting the entire folder or by holding ctrl and selecting each file.
The second way to add a folder to a space is via Administration > Content.
Let’s add one more folder to the CAJ space to see how it is done. To add a 2023 folder to the CAJ space, I will click on the Add folder icon and enter the name of the new folder. Be sure to confirm the path is correct. If not, select the correct path from the Path dropdown. Then click the Create button.
Once the folder is added, I can click on the eclipse for the 2023 folder and select Upload file to folder to upload files to this folder. If I used the Upload icon at the top, I would have to change the path to the 2023 folder before uploading my files.
This enhancement also lets me create subfolders as seen in the image below. I have a Population folder in the Census folder.
Now, let’s look at how we can load the data files in a Qlik Sense app using the folder structure. From the script editor in Qlik Sense, I can select the CAJ space and then click the Select data icon.
I can see the folder structure I have set up and I can drill down into the folders to select the file I want to load.
Notice that the file path in the script matches the hierarchical file structure I set up. This file structure can also be used when storing QVDs or inserting a QVS file.
I love this new feature in Qlik Cloud. Sometimes I have the need to organize my files by their source or in the example I shared in this blog by the year of the project. This allows me to organize my data in a way that makes sense for development. To learn more about this enhanced file management feature, check out Qlik Help.
Thanks,
Jennell
...View More
In this blog post, I will revisit a topic that I blogged about over a decade ago, the use of a silent legend. By default, a legend is created in a visualization when there are multiple dimensions and/or measures. The legend helps the user understand the visualization. Legends are helpful and without them, users may not comprehend the data in a visualization. But what do you do if have many visualizations on a sheet? Do you need a legend for each chart? Let’s look at the various ways a legend can be used and how a silent legend can reduce the clutter and give a sheet a cleaner look.
In the screen shot below, there are four visualizations at the bottom of the sheet with legends.
In this app, the legends are all the same because the visualizations are using the same asset class dimension. In this example, the legend does not need to be displayed for each visualization because it is redundant. Let’s see how this sheet will look if only one of the legends are kept on the sheet. A legend can easily be removed by toggling off Show Legend in the properties of the chart.
Here is what the sheet looks like with just one legend.
The sheet looks better with one legend versus four legends. This use of one legend for four charts, has decluttered the sheet and reduced repetitiveness. If a developer wants a legend to be displayed without expanding the chart, they need to ensure the visualization is large enough. Without the legends in the three stacked bar charts, less space is needed for the charts, thus they can be made smaller, if desired, to take up less space on the sheet. Since all the visualizations at the bottom of the sheet are using the same legend, the legend was placed with the first visualization, assuming a user is reading top to bottom, left to right.
Now, the beauty of a silent legend is that all visualization legends can be removed from a sheet. In the screenshot below, the four headings at the top of the sheet are colored based on the asset class they represent. So, Equity is green, Fixed Income is dark blue and so on.
This is an example of silent legend. The legend is implied by the asset class headings. This option looks even better and cleaner than the sheet with one legend.
The use of a silent legend is possible in this app because there are only four values for asset class. I have seen this work nicely with up to six values. Anything more may become too cumbersome and may require a legend to be used. Also, if the four visualizations at the bottom of the sheet used different dimensions, then multiple legends should be used. Legends are important and they should not be removed to add space if the chart is unreadable without it. What good is a pretty chart if you do not understand it.
Thanks,Jennell
...View More
If you’ve came across the initial Qlik Cloud Wordpress plugin on the Qlik Community Design blog and gave it a try, you probably have run into some issues with it. Today, I’m going to share a new updated version of the Qlik Cloud WordPress plugin that brings a more efficient way to embed Qlik Cloud analytics into your WordPress websites.
In this post, I'll walk you through the steps to install, configure, and use the new version of the plugin to bring your Qlik Cloud visualizations directly into your WP pages and posts.
Why the Update?
The previous version of our plugin relied on JWT tokens for auth, iframes (single integration API) and nebula.js for embedding, which worked but had limitations such as third-party cookies. Qlik Embed is the new embedding library and adopts better auth flows. In this version, I'm using OAuth impersonation to generate access token on the backend without need for users to interact with a login page.
Installation Steps
1. Install the Plugin
Log in to your WordPress Admin Dashboard.
Navigate to Plugins on the left sidebar.
Click on "Add New" at the top of the page.
Upload the zipped file (download it from GitHub here)
Locate the plugin and click "Install Now".
After installation, click "Activate".
Note: If you have the previous version installed, deactivate and delete it before installing the new one to avoid conflicts.
Configuring Qlik Cloud Wordpress Plugin
Before using the plugin, you'll need to set up OAuth impersonation in your Qlik Cloud tenant.
Create an OAuth Client
Log in to your Qlik Cloud tenant as an administrator.
Navigate to Management Console > Integrations > OAuth.
Click on "Create new" and fill in the required details:
Name: Give a recognizable name like "WordPress Integration".
Allowed Origins: Add your WordPress site's URL.
Select the right scopes to grant to the client from the Scopes list.
Check “Allow Machine-to-Machine (M2M)” and “Allow M2M user impersonation”
Change the consent method to Trusted
Save the client credentials (Client ID and Client Secret) to be used in WordPress Config.
Docs here: https://qlik.dev/authenticate/oauth/create/create-oauth-client-m2m-impersonation/
Make sure to read through the Guiding Principles of OAuth Impersonation:https://qlik.dev/authenticate/oauth/guiding-principles-oauth-impersonation
P.S: this method will create a number of anonymous users on your tenant and you need to implement a way to remove these users periodically (using a Qlik Application Automation / users API)
Configuring the Plugin
In your WordPress dashboard, go to Settings > Qlik Cloud Embed.
Fill in the required fields:
Host: e.g., https://your-tenant.region.qlikcloud.com.
Client ID: From the OAuth client you created.
Client Secret: From the OAuth client.
Click "Save Changes".
Using the Plugin
Embedding Sheets and Visualizations
With the plugin configured, you can now embed Qlik Cloud content using Shortcodes.
1. Embed an Entire Sheet/App
Use the [qlik-embed-app] shortcode:
[qlik-embed-app appid="1234-c56a-4062-ac50-377bba443e85" sheetid="12345-698f-449f-9a17-dca17eeadb71"]
Parameters:
appid: App ID
sheetid: Sheet ID
2. Embed Individual Visualizations/Objects
Use the [qlik-embed-object] shortcode:
[qlik-embed-object appid="1234-64317-8432" objectid="1234-5553-326432"]
Parameters:
appid: App ID
objectid: Object ID
3. Embed Selections bar
Use the [qlik-embed-selections] shortcode:
[qlik-embed-selections appid="1234-c56a-4062-ac50-377bba443e85"]
Parameters:
appid: App ID
Tip:
Finding IDs in Qlik Cloud
Open your app in Qlik Cloud.
Navigate to the sheet or object you want to embed.
In the URL, find the sheet ID
Sheet ID comes after /sheet/
For object, right click on the chart, click on Embed, and look for objectid under the chart preview.
You can download the plugin here:https://github.com/qlik-demo-team/wp-qlik-saas-plugin
P.S: this plugin is maintained by myself. If you find any bugs or issues, please report them to me or create an issue on Github and I'll do my best to resolve them quickly.
Thank you!
...View More
The new straight table, found in the Qlik Visualization bundle, has two new enhancements in Qlik Cloud. The first is expression-based text styling and the second is measure modifiers. Let’s look at how these new enhancements can be used.
With the first enhancement, columns in a straight table can be styled based on an expression. This is done in the properties of a column in the Text styleexpression.
There are four styles that can be applied in the expression. They are:
Bold: <b> or <B>
Italics: <i> or <I>
Underlined: <u> or <U>
Strikethrough: <s> or <S>
In the expression, the style can be in written in uppercase or lowercase letters and it should be enclosed in single quotes. Here is an example of an expression that can be used to bold the text in the Customer column if the Customer is Boombastic.
The results in the table look like this:
To bold all the text in the Customer column, '<b>' can be used in text style expression without the if statement.
In the example below, the text in the Discount column and the Product Name column is strikethrough if the discount is equal to 0. The same expression below is used in both columns to format the text.
Text styles can also be combined in an expression. In the example below, the text is bold, italicized and underlined if the Sales value is greater than $1,000. Notice that all the style codes are included in the single quotes.
Multiple styles can be used in the same expression based on different criteria as well. For example, Sales values can be bold if over $1,000 and strikethrough if under $100.
While text styles can be combined, use with care and use the text styles to highlight something in the data, not clutter it.
The second enhancement of the new straight table are measure modifiers. Modifiers are not new to Qlik Sense, but they are new to the straight table. In the properties of a measure, there is an option to add a modifier. The four modifier options are: accumulation, moving average, difference and relative numbers (see image below). When a modifier is selected, other modifier settings will be made available for developers to edit as needed.
Let’s look at each modifier briefly. The accumulation modifier will accumulate the measure value over dimension(s). In the table below, the Sales – Accumulation value will accumulate over the Year Month dimension.
The moving average modifier will average the measure value over a specified period. In the properties below, the moving average modifier is set to full. Also notice the output expression which shows the expression used for the modified measure – this is available for all modifier options.
With these settings, the results off the modifier will look like the table below. With every row, the Sales value is included to calculate the new moving average.
The difference modifier will display the difference between the measure value as seen in the table below. In this case, the difference between the previous row and current row values.
The relative numbers modifier will display relative percentages that can change based on the properties selected. In the example below, the year 2023 is selected. If the selection scope is set to current selections, then the resulting table will show the percentages for 2023 only.
If the selection is disregarded, then the percentages ignore the 2023 selection and show percentages across all the month year timeframes. Below in the resulting table, the percentages are a lot lower since they are across a larger dataset.
To learn more about these enhancements, check out Qlik help using the links below.
Straight table
Modifiers
Thanks,
Jennell
...View More
In previous blog posts (1, 2, 3), we explored different topics around Qlik's embedding library, qlik-embed, and how to integrate it seamlessly with OAuth for authentication. Today, we'll delve into the latest updates and new features, including embedding Qlik Answers, go over UI capabilities, and advanced configuration options.
Recap: What is qlik-embed?
qlik-embed is a versatile library designed to facilitate the embedding of Qlik Sense analytics into web applications. By using web components, it allows developers to easily integrate Qlik's powerful analytics capabilities without dealing with the complexities of traditional embedding methods. The library supports various authentication methods, including Qlik Cloud API keys, OAuth2 clients, and Qlik Sense Enterprise interactive login.
In our previous discussions, we highlighted the ease of use and the flexibility qlik-embed offers, supporting components such as chart, field, selections, and entire app.
New Feature: Embedding Qlik Answers
One of the most exciting additions to qlik-embed is the ability to embed Qlik Answers. Qlik Answers leverages AI to provide natural language querying capabilities, allowing users to interact with their data using conversational language (If you haven’t already checked that out, visit this Community post or watch this demo video). The new UI component ai/assistant enables this functionality directly right within your web app.
Here's an example of how you can integrate Qlik Answers into your application:
<qlik-embed
ui="ai/assistant"
assistant-id="<assistant-id>"
appearance="qlik-light"> // or "qlik-dark"
</qlik-embed>
This simple integration can greatly enhance user interaction by allowing them to ask questions and receive insights in real-time, making data exploration more intuitive and user-friendly.
More on UIs and Parameters
As I mentioned before, the qlik-embed framework supports a variety of UIs, each designed for specific purposes. Let’s take a quick overview on each one:
analytics/sheet: For embedding entire Qlik Sense sheets with full selectivity but without additional features like alerts or notes. (Supports sheets that contain only nebula.js visualizations, for a full list: see here: https://qlik.dev/embed/foundational-knowledge/visualizations/)<qlik-embed id="visualization" ui="analytics/sheet" app-id="13b05004-2752-4f39-a077-7a71c5816997" object-id="bdGHw"></qlik-embed>
analytics/chart: For embedding single chart objects or creating charts on the fly with better performance. (Supports nebula.js objects only, see full list above)<qlik-embed id="visualization" ui="analytics/chart" app-id="13b05004-2752-4f39-a077-7a71c5816997" object-id="hshG"></qlik-embed>
analytics/field: A lightweight listbox for a specific field (dimension or measure)(To find the library-id, you can add /options/developer to the URL when editing a sheet, right click on a object containing your master dimension or measure then click on Developer and look for the qLibraryId value)<qlik-embed id="visualization" ui="analytics/field" app-id="13b05004-2752-4f39-a077-7a71c5816997" library-id="BfXheUu" type="dimension"></qlik-embed>
analytics/selections: Displays a selection bar with controls for managing selections.<qlik-embed id="visualization" ui="analytics/selections" app-id="13b05004-2752-4f39-a077-7a71c5816997"></qlik-embed>
classic/app: Provides a full-featured Qlik Sense sheet analysis and authoring experience.<qlik-embed id="visualization" ui="classic/app" app-id="13b05004-2752-4f39-a077-7a71c5816997"></qlik-embed>
classic/chart: Backwards-compatible for single chart objects (legacy), including support for extensions.<qlik-embed id="visualization" ui="classic/chart" app-id="13b05004-2752-4f39-a077-7a71c5816997" object-id="hshG" iframe="true"></qlik-embed>
Each UI type can be configured with various parameters to customize the appearance and functionality. For example, you can set the theme, dimensions, measures, and even complex properties for charts.
Here’s an example of embedding a dynamic chart (See here for more info about Charts on the Fly)
<qlik-embed
ui="analytics/chart"
app-id="YOUR_APP_ID"
type="barchart"
dimensions='["Category"]'
measures='["Sum(Sales)"]'
properties='{"orientation": "horizontal"}'>
</qlik-embed>
This flexibility allows you to create highly dynamic and interactive dashboards that can adapt to users' needs in real-time.
Advanced Configuration: Context Parameters and Themes
A cool feature of qlik-embedis the ability to pass context parameters using the context__json attribute. This allows for more granular control over the embedded visualizations, enabling customization of themes, interactions, and other properties directly within the web component.
Reference my previous post about this here.
Accessing the App Model through qlik-embed
With qlik-embed, you can access the metadata of a Qlik Sense application, including, but not limited to, obtaining a list of sheets and adding them to a dropdown list element for instance.
Keep in mind that this won't work with the classic/app UI
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<style>
body,
html {
margin: 0;
padding: 0;
font-family: sans-serif;
font-size: 14px;
background-color: #f5f5f5;
color: #333;
height: 100%;
width: 100%;
}
.container {
padding: 8px;
gap: 8px;
position: relative;
flex: 1 0 auto;
display: flex;
flex-direction: column;
align-items: stretch;
box-sizing: border-box;
}
.classic-app {
height: 800px;
width: 1200px;
border: 1px solid #bbb;
flex-grow: 1;
border-radius: 3px;
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.2);
position: relative;
box-sizing: border-box;
overflow: auto;
position: relative;
}
.viz {
width: 1200px;
height: 900px;
padding: 16px;
border: 1px solid #bbb;
border-radius: 3px;
box-shadow: 1px 1px 10px rgba(0, 0, 0, 0.2);
position: relative;
}
</style>
<title>@qlik/embed-web-components example - using OAuth</title>
<script crossorigin="anonymous" type="application/javascript"
src="https://cdn.jsdelivr.net/npm/@qlik/embed-web-components"
data-host="https://YOUR_TENANT.us.qlikcloud.com" data-client-id="CLIENT_ID"
data-redirect-uri="https://localhost:3000/index_oauth_object.html" data-access-token-storage="session"></script>
<script type="module">
const embeddedObject = document.getElementById("visualization");
const refApi = await embeddedObject.getRefApi();
console.log('refApi -> ', refApi);
const doc = await refApi.getDoc();
const appSheetList = await doc.getSheetList();
//add the sheet references to a dropdown list
let dd = document.getElementById('sheetdrop');
dd.length = 0;
let defaultOption = document.createElement('option');
defaultOption.text = "Select a sheet to navigate to";
dd.add(defaultOption);
dd.selectedIndex = 0;
let option;
for (let i = 0; i < appSheetList.length; i++) {
option = document.createElement('option');
option.text = appSheetList[i].qMeta.title;
option.value = appSheetList[i].qMeta.id;
dd.add(option);
}
//add a listener to change the object-id property in the qlik-embed element
dd.addEventListener("change", function () {
if (dd.selectedIndex > 0) {
let selOption = dd.options[dd.selectedIndex];
console.log(selOption.value);
embeddedObject.setAttribute('object-id', selOption.value);
}
});
</script>
</head>
<body>
<div id="main-app">
<div class="container">
<h1>@qlik/embed-web-components Example</h1>
</div>
<div>
<select id="sheetdrop" name="SheetList">
</select>
</div>
<div id="analytics-chart" class="container">
<div class="viz">
<qlik-embed id="visualization" ui="analytics/sheet" app-id="27018b4a-eaa7-4658-a8c2-ecf48d321371"
object-id="d568340d-1264-473e-bbdf-68d2555f007e"></qlik-embed>
</div>
</div>
</body>
</html>
The continuous evolution of qlik-embed brings exciting new features that enhance the integration of Qlik analytics into web applications. Stay tuned for more updates and explore the full potential of qlik-embedon qlik.dev.
...View More