Examples

Browser-based integration examples for Qlik Cloud and Qlik Sense Enterprise using modern web frameworks.

🌐 Browser-Only Examples

All examples are designed for browser environments only. The Qlik SDK supports modern module formats (ESM, CommonJS, UMD) and works with Qlik Cloud and Qlik Sense Enterprise.

All
Qlik Cloud
Qlik Enterprise
Vanilla JS
React
Vue

Qlik Cloud Integration with Vanilla JavaScript

Qlik Cloud
Vanilla JS

Connect to Qlik Cloud using vanilla JavaScript with the browser-based SDK. This example demonstrates authentication, app loading, and basic visualization embedding.

Features

  • • Qlik Cloud authentication
  • • App and object embedding
  • • Session management
  • • Error handling
  • • Responsive layout

Requirements

Modern Browser
Qlik Cloud Tenant
Web Integration ID
HTTPS

1. Setup HTML Page

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Qlik Cloud Integration</title>
    <style>
        body { margin: 0; font-family: Arial, sans-serif; }
        .container { max-width: 1200px; margin: 0 auto; padding: 20px; }
        .chart-container { 
            width: 100%; height: 400px; border: 1px solid #ddd; 
            margin: 20px 0; border-radius: 8px; 
        }
        #status { padding: 10px; border-radius: 4px; margin: 10px 0; }
        .success { background-color: #d4edda; color: #155724; }
        .error { background-color: #f8d7da; color: #721c24; }
    </style>
</head>
<body>
    <div class="container">
        <h1>Qlik Cloud Dashboard</h1>
        <div id="status">Initializing...</div>
        
        <div class="chart-container" id="chart1">
            <p style="text-align: center; padding: 150px 0; color: #666;">
                Chart will load here...
            </p>
        </div>
        
        <div class="chart-container" id="chart2">
            <p style="text-align: center; padding: 150px 0; color: #666;">
                Second chart will load here...
            </p>
        </div>
    </div>

    <!-- Load Qlik SDK -->
    <script src="https://cdn.jsdelivr.net/npm/qlik@5.0.0/dist/qlik.min.js"></script>
    <script src="./app.js"></script>
</body>
</html>

2. JavaScript Integration (app.js)

javascript
// app.js - Qlik Cloud Integration
class QlikCloudDashboard {
    constructor() {
        this.qlik = null;
        this.app = null;
        this.config = {
            // Replace with your Qlik Cloud tenant URL
            host: 'your-tenant.us.qlikcloud.com',
            // Replace with your Web Integration ID from Qlik Cloud Console
            webIntegrationId: 'your-web-integration-id',
            // Replace with your app ID
            appId: 'your-app-id'
        };
    }

    async initialize() {
        const statusEl = document.getElementById('status');
        
        try {
            statusEl.textContent = 'Connecting to Qlik Cloud...';
            statusEl.className = '';
            
            // Initialize Qlik SDK
            this.qlik = new window.Qlik({
                host: this.config.host,
                webIntegrationId: this.config.webIntegrationId
            });

            // Authenticate to Qlik Cloud
            await this.qlik.authenticate();
            
            statusEl.textContent = 'Connected! Loading app...';
            statusEl.className = 'success';
            
            // Open the app
            this.app = await this.qlik.openApp(this.config.appId);
            
            statusEl.textContent = 'App loaded! Rendering charts...';
            
            // Load visualizations
            await this.loadCharts();
            
            statusEl.textContent = 'Dashboard ready!';
            
        } catch (error) {
            console.error('Qlik initialization failed:', error);
            statusEl.textContent = `Error: ${error.message}`;
            statusEl.className = 'error';
        }
    }

    async loadCharts() {
        try {
            // Load first chart - replace 'chart-object-id-1' with actual object ID
            const chart1 = await this.app.getObject('chart-object-id-1');
            await chart1.show('chart1');
            
            // Load second chart - replace 'chart-object-id-2' with actual object ID
            const chart2 = await this.app.getObject('chart-object-id-2');
            await chart2.show('chart2');
            
        } catch (error) {
            console.error('Failed to load charts:', error);
            document.getElementById('status').textContent = `Chart loading error: ${error.message}`;
            document.getElementById('status').className = 'error';
        }
    }

    // Method to handle selections and interactions
    async makeSelection(fieldName, values) {
        if (this.app) {
            const field = await this.app.field(fieldName);
            await field.select(values);
        }
    }
}

// Initialize when page loads
document.addEventListener('DOMContentLoaded', () => {
    const dashboard = new QlikCloudDashboard();
    dashboard.initialize();
});

3. Configuration Steps

text
Steps to configure this example:

1. Get Qlik Cloud Credentials:
   • Log into your Qlik Cloud tenant
   • Go to Console > Web Integrations
   • Create a new Web Integration ID
   • Note your tenant URL (e.g., your-tenant.us.qlikcloud.com)

2. Update Configuration:
   • Replace 'your-tenant.us.qlikcloud.com' with your tenant URL
   • Replace 'your-web-integration-id' with your actual Web Integration ID
   • Replace 'your-app-id' with an actual app ID from your tenant

3. Object IDs:
   • Open your app in Qlik Cloud
   • Right-click on charts > Developer > Copy Object ID
   • Replace 'chart-object-id-1' and 'chart-object-id-2' with actual IDs

4. Deploy:
   • Host the HTML file on HTTPS (required for Qlik Cloud)
   • Test the integration in your browser

4. Expected Output

text
When successful, you'll see:

āœ… Status: "Dashboard ready!"
āœ… Two interactive Qlik charts embedded in the page
āœ… Charts respond to user interactions (selections, filters)
āœ… Session maintained across page refreshes

Common Issues:
āŒ CORS errors → Check Web Integration ID and HTTPS
āŒ Authentication popup blocked → Allow popups for your domain
āŒ Charts not loading → Verify object IDs and app permissions

Key Concepts Demonstrated

Qlik Cloud Authentication - Using Web Integration ID for secure browser-based auth
Chart Embedding - Loading and displaying Qlik visualizations in web pages
Error Handling - Proper error handling for connection and loading failures
Session Management - Maintaining Qlik session state in the browser
HTTPS Requirement - Browser security requirements for Qlik Cloud integration

Qlik Sense Enterprise Integration

Qlik Enterprise
On-Premise

Connect to Qlik Sense Enterprise on-premise deployment using certificate authentication and virtual proxy configuration.

Features

  • • Certificate-based authentication
  • • Virtual proxy configuration
  • • Session management
  • • Cross-domain integration
  • • Enterprise security compliance

Requirements

Qlik Sense Enterprise
Virtual Proxy
HTTPS
Valid Certificate

1. HTML Setup for Enterprise

html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Qlik Sense Enterprise Dashboard</title>
    <style>
        body { margin: 0; font-family: Arial, sans-serif; background: #f5f5f5; }
        .container { max-width: 1400px; margin: 0 auto; padding: 20px; }
        .header { background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
        .dashboard-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 20px; }
        .chart-container { 
            background: white; border-radius: 8px; padding: 20px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1); height: 400px; 
        }
        .full-width { grid-column: 1 / -1; }
        #status { padding: 12px; border-radius: 6px; margin: 15px 0; font-weight: 500; }
        .success { background: #d1f2d1; color: #0d5016; border: 1px solid #4caf50; }
        .error { background: #f8d7da; color: #721c24; border: 1px solid #dc3545; }
        .loading { background: #fff3cd; color: #856404; border: 1px solid #ffc107; }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>Qlik Sense Enterprise Dashboard</h1>
            <p>Connected to on-premise Qlik Sense deployment</p>
            <div id="status" class="loading">Initializing connection to Qlik Sense Enterprise...</div>
        </div>
        
        <div class="dashboard-grid">
            <div class="chart-container" id="kpi-chart">
                <h3>Key Performance Indicators</h3>
                <div id="kpi-content">Loading KPI chart...</div>
            </div>
            
            <div class="chart-container" id="trend-chart">
                <h3>Sales Trend Analysis</h3>
                <div id="trend-content">Loading trend chart...</div>
            </div>
            
            <div class="chart-container full-width" id="table-chart">
                <h3>Detailed Data Table</h3>
                <div id="table-content">Loading data table...</div>
            </div>
        </div>
    </div>

    <!-- Load Qlik SDK -->
    <script src="https://cdn.jsdelivr.net/npm/qlik@5.0.0/dist/qlik.min.js"></script>
    <script src="./enterprise-app.js"></script>
</body>
</html>

2. JavaScript Integration (enterprise-app.js)

javascript
// enterprise-app.js - Qlik Sense Enterprise Integration
class QlikEnterpriseIntegration {
    constructor() {
        this.qlik = null;
        this.app = null;
        this.config = {
            // Replace with your Qlik Sense server details
            host: 'qlik-server.company.com',
            prefix: '/virtual-proxy/',  // Virtual proxy prefix
            port: 443,
            isSecure: true,
            
            // Authentication settings for Enterprise
            authentication: {
                method: 'certificate', // or 'header' for header authentication
                userId: 'DOMAIN\\username',  // For Windows domain users
                // For certificate auth, include certificate details
                certificate: {
                    pfx: '/path/to/certificate.pfx',  // Not used in browser
                    passphrase: 'cert-password'       // Not used in browser
                }
            },
            
            // App configuration
            appId: 'your-qlik-sense-app-id',
            
            // Object IDs for visualizations
            objects: {
                kpiChart: 'kpi-object-id',
                trendChart: 'trend-object-id', 
                dataTable: 'table-object-id'
            }
        };
    }

    async initialize() {
        const statusEl = document.getElementById('status');
        
        try {
            statusEl.textContent = 'Connecting to Qlik Sense Enterprise...';
            statusEl.className = 'loading';
            
            // Configure Qlik SDK for Enterprise
            this.qlik = new window.Qlik({
                host: this.config.host,
                prefix: this.config.prefix,
                port: this.config.port,
                isSecure: this.config.isSecure,
                
                // Enterprise-specific configuration
                authentication: {
                    method: 'session',  // Browser uses session-based auth
                    userId: this.config.authentication.userId
                }
            });

            // For Enterprise, authentication typically happens via proxy
            // The browser will redirect to authentication if needed
            statusEl.textContent = 'Authenticating via Enterprise proxy...';
            
            await this.qlik.authenticate();
            
            statusEl.textContent = 'Connected! Opening application...';
            statusEl.className = 'success';
            
            // Open the Qlik Sense application
            this.app = await this.qlik.openApp(this.config.appId);
            
            statusEl.textContent = 'App opened! Loading visualizations...';
            
            // Load all visualizations
            await this.loadDashboard();
            
            statusEl.textContent = 'Enterprise dashboard ready!';
            
        } catch (error) {
            console.error('Qlik Enterprise initialization failed:', error);
            statusEl.textContent = `Connection Error: ${error.message}`;
            statusEl.className = 'error';
            
            // Provide helpful error messages for common Enterprise issues
            this.handleEnterpriseError(error, statusEl);
        }
    }

    async loadDashboard() {
        const loadPromises = [
            this.loadVisualization(this.config.objects.kpiChart, 'kpi-content', 'KPI Chart'),
            this.loadVisualization(this.config.objects.trendChart, 'trend-content', 'Trend Chart'),
            this.loadVisualization(this.config.objects.dataTable, 'table-content', 'Data Table')
        ];
        
        await Promise.all(loadPromises);
    }

    async loadVisualization(objectId, containerId, displayName) {
        try {
            const object = await this.app.getObject(objectId);
            const container = document.getElementById(containerId);
            
            if (!container) {
                console.warn(`Container ${containerId} not found for ${displayName}`);
                return;
            }
            
            await object.show(container);
            console.log(`āœ… ${displayName} loaded successfully`);
            
        } catch (error) {
            console.error(`Failed to load ${displayName}:`, error);
            const container = document.getElementById(containerId);
            if (container) {
                container.innerHTML = `<div style="color: #dc3545; text-align: center; padding: 50px;">
                    <strong>Error loading ${displayName}</strong><br>
                    ${error.message}
                </div>`;
            }
        }
    }

    handleEnterpriseError(error, statusEl) {
        let helpText = '';
        
        if (error.message.includes('CORS')) {
            helpText = '\n\nTip: Check virtual proxy CORS settings and whitelist your domain.';
        } else if (error.message.includes('authentication')) {
            helpText = '\n\nTip: Verify authentication method and user permissions.';
        } else if (error.message.includes('certificate')) {
            helpText = '\n\nTip: Check certificate configuration and trust chain.';
        }
        
        statusEl.textContent += helpText;
    }

    // Method to make selections in the Enterprise app
    async makeSelection(fieldName, values) {
        if (!this.app) return;
        
        try {
            const field = await this.app.field(fieldName);
            await field.select(values);
            console.log(`Selection made in ${fieldName}:`, values);
        } catch (error) {
            console.error('Selection failed:', error);
        }
    }

    // Method to clear all selections
    async clearAllSelections() {
        if (!this.app) return;
        
        try {
            await this.app.clearAll();
            console.log('All selections cleared');
        } catch (error) {
            console.error('Clear selections failed:', error);
        }
    }
}

// Initialize when page loads
document.addEventListener('DOMContentLoaded', () => {
    const enterprise = new QlikEnterpriseIntegration();
    enterprise.initialize();
    
    // Make the enterprise instance globally available for debugging
    window.qlikEnterprise = enterprise;
});

3. Enterprise Configuration Steps

text
Configuration for Qlik Sense Enterprise:

1. Virtual Proxy Setup:
   • Create virtual proxy in QMC (Qlik Management Console)
   • Configure authentication method (Windows, SAML, JWT, etc.)
   • Set up CORS whitelist to include your web app domain
   • Configure session cookies and timeout settings

2. Authentication Method:
   • Windows Authentication: Uses domain credentials
   • Certificate Authentication: Requires client certificates
   • Header Authentication: Custom header-based auth
   • SAML/OIDC: Single sign-on integration

3. Update JavaScript Configuration:
   • Replace 'qlik-server.company.com' with your Qlik server hostname
   • Update virtual proxy prefix (e.g., '/sales/', '/analytics/')
   • Set correct port (default: 443 for HTTPS)
   • Configure authentication method matching your proxy

4. App and Object Setup:
   • Get App ID from Qlik Sense Hub or via API
   • Get Object IDs by right-clicking charts in Qlik Sense
   • Ensure user has access permissions to the app and objects

5. Security Considerations:
   • Use HTTPS for all communications
   • Configure proper CORS settings
   • Implement proper certificate trust chains
   • Test authentication flow thoroughly

4. Expected Behavior

text
Successful Enterprise Integration Results:

āœ… Authentication Flow:
   - Browser redirects to enterprise authentication (if needed)
   - Session established with virtual proxy
   - User credentials validated by enterprise identity provider

āœ… Dashboard Loading:
   - Three visualization panels load with real data
   - KPI chart shows key performance metrics
   - Trend chart displays time-series analysis
   - Data table shows detailed records

āœ… Interactive Features:
   - Click-to-filter functionality across all charts
   - Selection state synchronized across visualizations
   - Clear selections button resets all filters

Common Enterprise Issues:
āŒ Virtual proxy not configured → 404 or connection errors
āŒ CORS not whitelisted → Cross-origin request blocked
āŒ Authentication mismatch → Redirect loops or auth failures
āŒ Certificate issues → SSL/TLS handshake failures
āŒ Insufficient permissions → Object loading failures

Key Enterprise Features

Virtual Proxy Integration - Seamless integration with enterprise proxy configuration
Enterprise Authentication - Support for Windows, SAML, certificate-based auth
Session Management - Proper handling of enterprise session lifecycle
CORS Configuration - Cross-origin support for web applications
Security Compliance - Enterprise-grade security and access controls

React + Qlik Cloud Integration

React
TypeScript

Build a modern React application with TypeScript that integrates Qlik Cloud visualizations using hooks and context.

Features

  • • React hooks for Qlik integration
  • • TypeScript for type safety
  • • Context-based state management
  • • Responsive component design
  • • Error boundary handling

Tech Stack

React 18
TypeScript
Qlik SDK
Vite

1. Project Setup

bash
# Create new React app with TypeScript
npm create vite@latest qlik-react-app -- --template react-ts
cd qlik-react-app

# Install dependencies
npm install
npm install qlik

# Install additional UI dependencies (optional)
npm install @radix-ui/react-dialog @radix-ui/react-toast

2. Qlik Context Provider

typescript
// src/contexts/QlikContext.tsx
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
import Qlik from 'qlik';

interface QlikContextType {
  qlik: Qlik | null;
  app: any | null;
  isConnected: boolean;
  isLoading: boolean;
  error: string | null;
  connect: () => Promise<void>;
  disconnect: () => void;
}

const QlikContext = createContext<QlikContextType | undefined>(undefined);

interface QlikProviderProps {
  children: ReactNode;
  config: {
    host: string;
    webIntegrationId: string;
    appId: string;
  };
}

export const QlikProvider: React.FC<QlikProviderProps> = ({ children, config }) => {
  const [qlik, setQlik] = useState<Qlik | null>(null);
  const [app, setApp] = useState<any | null>(null);
  const [isConnected, setIsConnected] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const connect = async () => {
    setIsLoading(true);
    setError(null);
    
    try {
      // Initialize Qlik SDK
      const qlikInstance = new Qlik({
        host: config.host,
        webIntegrationId: config.webIntegrationId
      });

      // Authenticate
      await qlikInstance.authenticate();
      setQlik(qlikInstance);

      // Open app
      const appInstance = await qlikInstance.openApp(config.appId);
      setApp(appInstance);

      setIsConnected(true);
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to connect to Qlik');
      console.error('Qlik connection failed:', err);
    } finally {
      setIsLoading(false);
    }
  };

  const disconnect = () => {
    if (qlik) {
      // Clean up connection
      setQlik(null);
      setApp(null);
      setIsConnected(false);
    }
  };

  // Auto-connect on mount
  useEffect(() => {
    connect();
    
    // Cleanup on unmount
    return () => disconnect();
  }, []);

  const value: QlikContextType = {
    qlik,
    app,
    isConnected,
    isLoading,
    error,
    connect,
    disconnect
  };

  return (
    <QlikContext.Provider value={value}>
      {children}
    </QlikContext.Provider>
  );
};

export const useQlik = () => {
  const context = useContext(QlikContext);
  if (context === undefined) {
    throw new Error('useQlik must be used within a QlikProvider');
  }
  return context;
};

3. Qlik Chart Component

typescript
// src/components/QlikChart.tsx
import React, { useEffect, useRef, useState } from 'react';
import { useQlik } from '../contexts/QlikContext';

interface QlikChartProps {
  objectId: string;
  title?: string;
  className?: string;
}

export const QlikChart: React.FC<QlikChartProps> = ({ 
  objectId, 
  title, 
  className = '' 
}) => {
  const { app, isConnected } = useQlik();
  const chartRef = useRef<HTMLDivElement>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let isMounted = true;

    const loadChart = async () => {
      if (!app || !chartRef.current || !isConnected) {
        return;
      }

      setIsLoading(true);
      setError(null);

      try {
        // Get the Qlik object
        const qlikObject = await app.getObject(objectId);
        
        // Only proceed if component is still mounted
        if (!isMounted) return;

        // Clear any existing content
        if (chartRef.current) {
          chartRef.current.innerHTML = '';
          
          // Show the visualization in the container
          await qlikObject.show(chartRef.current);
        }
      } catch (err) {
        if (isMounted) {
          const errorMessage = err instanceof Error ? err.message : 'Failed to load chart';
          setError(errorMessage);
          console.error(`Error loading chart ${objectId}:`, err);
        }
      } finally {
        if (isMounted) {
          setIsLoading(false);
        }
      }
    };

    loadChart();

    // Cleanup function
    return () => {
      isMounted = false;
      if (chartRef.current) {
        chartRef.current.innerHTML = '';
      }
    };
  }, [app, objectId, isConnected]);

  if (!isConnected) {
    return (
      <div className={`qlik-chart-placeholder ${className}`}>
        <div className="text-center text-gray-500 p-8">
          <div>Not connected to Qlik</div>
        </div>
      </div>
    );
  }

  if (error) {
    return (
      <div className={`qlik-chart-error ${className}`}>
        <div className="text-center text-red-500 p-8">
          <div className="font-semibold">Error loading chart</div>
          <div className="text-sm mt-2">{error}</div>
        </div>
      </div>
    );
  }

  return (
    <div className={`qlik-chart-container ${className}`}>
      {title && (
        <h3 className="text-lg font-semibold mb-4 text-gray-800">
          {title}
        </h3>
      )}
      
      {isLoading && (
        <div className="absolute inset-0 flex items-center justify-center bg-white bg-opacity-75">
          <div className="text-center">
            <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500 mx-auto mb-2"></div>
            <div className="text-gray-600">Loading chart...</div>
          </div>
        </div>
      )}
      
      <div 
        ref={chartRef} 
        className="qlik-chart w-full h-full min-h-[300px] relative"
        style={{ minHeight: '300px' }}
      />
    </div>
  );
};

4. Main App Component

typescript
// src/App.tsx
import React from 'react';
import { QlikProvider } from './contexts/QlikContext';
import { QlikChart } from './components/QlikChart';
import './App.css';

// Configuration - replace with your Qlik Cloud details
const qlikConfig = {
  host: 'your-tenant.us.qlikcloud.com',
  webIntegrationId: 'your-web-integration-id',
  appId: 'your-app-id'
};

function App() {
  return (
    <QlikProvider config={qlikConfig}>
      <div className="App">
        <header className="app-header">
          <h1>React + Qlik Cloud Dashboard</h1>
          <p>Modern React integration with TypeScript</p>
        </header>

        <main className="dashboard-grid">
          <div className="chart-section">
            <QlikChart 
              objectId="sales-kpi-object-id" 
              title="Sales KPIs"
              className="chart-card"
            />
          </div>

          <div className="chart-section">
            <QlikChart 
              objectId="trend-chart-object-id" 
              title="Revenue Trends"
              className="chart-card"
            />
          </div>

          <div className="chart-section full-width">
            <QlikChart 
              objectId="data-table-object-id" 
              title="Detailed Analysis"
              className="chart-card"
            />
          </div>
        </main>
      </div>
    </QlikProvider>
  );
}

export default App;

5. CSS Styling (App.css)

css
/* src/App.css */
.App {
  max-width: 1400px;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}

.app-header {
  background: white;
  padding: 2rem;
  border-radius: 12px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  margin-bottom: 2rem;
  text-align: center;
}

.app-header h1 {
  color: #1f2937;
  margin: 0 0 0.5rem 0;
  font-size: 2.5rem;
}

.app-header p {
  color: #6b7280;
  margin: 0;
  font-size: 1.1rem;
}

.dashboard-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1.5rem;
}

.chart-section {
  background: white;
  border-radius: 12px;
  padding: 1.5rem;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  min-height: 400px;
}

.chart-section.full-width {
  grid-column: 1 / -1;
  min-height: 500px;
}

.chart-card {
  width: 100%;
  height: 100%;
}

/* Responsive design */
@media (max-width: 768px) {
  .dashboard-grid {
    grid-template-columns: 1fr;
  }
  
  .app-header h1 {
    font-size: 2rem;
  }
  
  .chart-section {
    min-height: 300px;
  }
}

Key React Integration Features

React Hooks Pattern - Custom useQlik hook for easy integration
Context-based State - Global Qlik state management across components
TypeScript Safety - Full type safety for props and state
Error Boundaries - Graceful error handling and user feedback
Component Reusability - Reusable QlikChart component for any visualization
Lifecycle Management - Proper cleanup on component unmount