
Syncfusion React Heatmap
- 339 installs
- 3 repo stars
- Updated July 28, 2026
- syncfusion/react-ui-components-skills
Use syncfusion-react-heatmap for development tasks
About
syncfusion-react-heatmap: A skill for development. This provides functionality for development workflows.
- syncfusion-react-heatmap
Syncfusion React Heatmap by the numbers
- 339 all-time installs (skills.sh)
- +22 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #1,186 of 4,347 Backend & APIs skills by installs in the Skillselion catalog
- Data as of Jul 29, 2026 (Skillselion catalog sync)
npx skills add https://github.com/syncfusion/react-ui-components-skills --skill syncfusion-react-heatmapAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 339 |
|---|---|
| repo stars | ★ 3 |
| Last updated | July 28, 2026 |
| Repository | syncfusion/react-ui-components-skills ↗ |
What it does
Use syncfusion-react-heatmap for development tasks
Files
Implementing Syncfusion React HeatMap Chart
The HeatMap component visualizes two-dimensional data using color gradients or fixed colors, making it ideal for analyzing patterns, correlations, and distributions across matrix data. Perfect for displaying heat patterns, activity matrices, performance data, and temporal correlations.
When to Use This Skill
- Visualizing 2D data patterns - Display matrix data with color-coded cells
- Creating heatmaps - Build interactive heatmaps with custom color schemes
- Analyzing correlations - Show relationships between row and column variables
- Displaying time-series patterns - Visualize activity over time periods
- Performance monitoring - Display metrics across multiple dimensions
- Data exploration - Reveal patterns in large datasets at a glance
- Configuring axes - Set up numerical, categorical, or datetime axes
- Customizing appearance - Apply custom colors, legends, and styling
- Handling user interaction - Implement selection, tooltips, and event handling
- Accessibility - Ensure keyboard navigation and screen reader support
Documentation and Navigation Guide
Getting Started
📄 Read: references/getting-started.md
- Installation and setup steps
- Vite/React project configuration
- CSS imports and theme selection
- Basic component initialization
- When: Starting a new HeatMap implementation or setting up dependencies
Data Binding & Setup
📄 Read: references/data-binding.md
- JSON data format and structure
- 2D array binding
- Data transformation techniques
- Loading and binding data dynamically
- When: Preparing data for the heatmap or learning data formats
Axes Configuration
📄 Read: references/axes-configuration.md
- Numerical, categorical, and datetime axis types
- Axis properties and customization
- Inverted and opposed axis positioning
- Axis intervals and label formatting
- When: Setting up row/column headers or configuring axis behavior
Legend, Appearance & Styling
📄 Read: references/legend-and-appearance.md
- Legend placement, format, and customization
- Color palettes and gradient configuration
- Sizing and dimension properties
- Rendering modes (SVG vs Canvas switching)
- Theme styling and CSS customization
- When: Customizing visual appearance, colors, or legends
Interaction & Selection
📄 Read: references/interaction-and-selection.md
- Selection modes and cell highlighting
- Mouse events and event handlers
- Tooltip configuration and customization
- Cell interaction patterns and best practices
- When: Implementing user interaction or handling cell clicks/hovers
Advanced Features & Events
📄 Read: references/advanced-features.md
- Bubble heatmap implementation
- Complete event handling (select, click, hover, created)
- Automatic rendering mode switching
- Performance optimization for large datasets
- Custom rendering and cell styling
- When: Implementing advanced features or optimizing performance
API Reference
📄 Read: references/api-reference.md
- Comprehensive component API: props, methods, events, and model schemas
- Quick lookup for
cellSettings,legendSettings,paletteSettings,xAxis,yAxis,titleSettings,tooltipSettings, and common methods likeexport,print,clearSelection - When: Adding or validating props, wiring events, or implementing advanced customizations
Accessibility & Troubleshooting
📄 Read: references/accessibility-and-troubleshooting.md
- WCAG compliance and accessibility features
- Keyboard navigation support
- ARIA attributes and screen reader support
- Common issues and solutions
- Migration from EJ1 to EJ2
- When: Ensuring accessibility or resolving issues
Quick Start
import * as React from 'react';
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
import '@syncfusion/ej2-base/styles/material.css';
export function App() {
const data = [
[73, 39, 26, 39, 94],
[93, 58, 53, 38, 26],
[54, 39, 26, 40, 42]
];
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{ labels: ['A', 'B', 'C', 'D', 'E'] }}
yAxis={{ labels: ['X', 'Y', 'Z'] }}
showTooltip={true}
cellRender={(args) => {
args.displayText = args.value + '%';
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}
export default App;Common Patterns
Pattern 1: Basic Data Visualization
// Visualize simple 2D data with default styling
<HeatMapComponent
dataSource={data}
xAxis={{ labels: xLabels }}
yAxis={{ labels: yLabels }}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Pattern 2: Custom Colors, Legend, and Tooltips
// Apply custom color palette with legend and styled tooltips
<HeatMapComponent
dataSource={data}
paletteSettings={{
type: 'Gradient',
palette: [
{ value: 0, color: '#3498db' },
{ value: 50, color: '#2ecc71' },
{ value: 100, color: '#e74c3c' }
]
}}
legendSettings={{ position: 'Right', width: '150px' }}
showTooltip={true}
tooltipSettings={{
fill: '#F5F5F5',
textStyle: { color: '#333333', size: '13px' },
border: { width: 1, color: '#999999' }
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Pattern 3: Interactive Cell Handling
// Handle cell selection and display selected data
<HeatMapComponent
dataSource={data}
cellSelected={(args) => {
console.log(`Cell [${args.row}, ${args.column}] selected: ${args.value}`);
}}
cellRender={(args) => {
args.displayText = args.value + ' units';
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Key Props
| Prop | Type | Purpose | Example |
|---|---|---|---|
dataSource | Array | 2D data array or JSON | [[1,2],[3,4]] |
xAxis | Object | Column axis configuration | { labels: ['A', 'B'] } |
yAxis | Object | Row axis configuration | { labels: ['X', 'Y'] } |
paletteSettings | Object | Color palette and gradient configuration | { type: 'Gradient', palette: [{value: 0, color: '#blue'}] } |
cellRender | Function | Custom cell formatting | Format display text |
cellSelected | Function | Selection event handler | Track user selection |
legendSettings | Object | Legend placement/format | { position: 'Right' } |
showTooltip | Boolean | Enable/disable tooltips | true or false |
tooltipSettings | Object | Tooltip styling (fill, textStyle, border) | { fill: '#F5F5F5', textStyle: { color: '#333' } } |
renderingMode | String | SVG or Canvas | 'Canvas' for large datasets |
Common Use Cases
1. Performance Dashboard - Display metrics across departments and time periods 2. Correlation Matrix - Visualize relationships between variables 3. Activity Heatmap - Show user engagement patterns by day/hour 4. Gene Expression - Analyze biological data with color intensity 5. Traffic Pattern - Visualize network/website traffic distribution 6. Survey Results - Display response patterns across questions and demographics
---
Accessibility & Troubleshooting
Table of Contents
- Accessibility Features
- Enable Accessibility
- Provide Semantic Context
- Alternative Text Content
- WCAG Compliance
- Color Contrast
- Color + Pattern Support
- Font Size and Readability
- Keyboard Navigation
- Enable Keyboard Interaction
- Focus Indicators
- Screen Reader Support
- ARIA Labels
- Meaningful Tooltip Content
- Data Table as Fallback
- Common Issues
- Troubleshooting Guide
- Issue 1: HeatMap Not Rendering
- Issue 2: Styles Not Applied
- Issue 3: Axes Labels Overlapping
- Issue 4: Large Dataset Performance
- Issue 5: Tooltips Not Showing
- Migration from EJ1
- EJ1 vs EJ2 Differences
- Basic Migration Example
- Data Format Migration
- Event Name Changes
- Complete Migration Template
Accessibility Features
Enable Accessibility
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
export function AccessibleHeatmap() {
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
title: { text: 'Quarters' } // Label for screen readers
}}
yAxis={{
labels: ['North', 'South', 'East'],
title: { text: 'Regions' } // Label for screen readers
}}
title={{ text: 'Sales Data Heatmap' }} // Main title for context
showTooltip= {true}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Provide Semantic Context
<div>
<h1>Sales Performance Analysis</h1>
<p>
This heatmap shows quarterly sales data across three regions.
Darker colors indicate higher sales volumes.
</p>
<HeatMapComponent
id='heatmap'
dataSource={data}
title={{ text: 'Quarterly Sales by Region' }}
ariaLabel='Sales heatmap with quarterly data by region'
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
<p>
<strong>Color meaning:</strong> Blue indicates low sales, red indicates high sales.
</p>
</div>Alternative Text Content
export function AccessibleWithAlternative() {
const data = [
{ row: 'North', column: 'Q1', value: 150 },
{ row: 'North', column: 'Q2', value: 200 },
{ row: 'South', column: 'Q1', value: 100 },
{ row: 'South', column: 'Q2', value: 180 }
];
return (
<div>
{/* Visual heatmap */}
<HeatMapComponent id='heatmap' dataSource={data}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
{/* Alternative text representation */}
<div role='region' aria-label='Heatmap data table'>
<h3>Data Table (Alternative Format)</h3>
<table>
<thead>
<tr>
<th>Region</th>
<th>Q1</th>
<th>Q2</th>
</tr>
</thead>
<tbody>
<tr>
<td>North</td>
<td>150</td>
<td>200</td>
</tr>
<tr>
<td>South</td>
<td>100</td>
<td>180</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}WCAG Compliance
Color Contrast
import '@syncfusion/ej2-base/styles/material.css';
export function HighContrastHeatmap() {
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
// High contrast colors (WCAG AA compliant)
paletteSettings={{
palette: [{ value: 0, color: '#FFFFFF' },
{ value: 50, color: '#808080' }, // Gray
{ value: 100, color: '#000000' }
]
}}
legendSettings={{
textStyle: {
color: '#000000', // High contrast text
size: '14px'
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Color + Pattern Support
export function PatternHeatmap() {
const patterns = ['/', '\\', '|', '-', 'x'];
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
cellRender={(args) => {
// Not just color - also add pattern
const patternIndex = Math.floor(args.value / 20) % patterns.length;
args.displayText = patterns[patternIndex];
// Add visual indicator
if (args.value > 80) {
args.displayText += '●'; // Bullet for very high values
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Font Size and Readability
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
textStyle: {
size: '14px', // At least 14px
fontWeight: 'bold' // Better readability
}
}}
yAxis={{
labels: ['North', 'South', 'East'],
textStyle: {
size: '14px',
fontWeight: 'bold'
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Keyboard Navigation
Enable Keyboard Interaction
export function KeyboardAccessibleHeatmap() {
const [focusedCell, setFocusedCell] = useState(null);
const handleKeyDown = (event) => {
if (!focusedCell) return;
const { row, col } = focusedCell;
switch(event.key) {
case 'ArrowUp':
setFocusedCell({ row: Math.max(0, row - 1), col });
event.preventDefault();
break;
case 'ArrowDown':
setFocusedCell({ row: row + 1, col });
event.preventDefault();
break;
case 'ArrowLeft':
setFocusedCell({ row, col: Math.max(0, col - 1) });
event.preventDefault();
break;
case 'ArrowRight':
setFocusedCell({ row, col: col + 1 });
event.preventDefault();
break;
case 'Enter':
case ' ':
// Activate cell
handleCellActivation(row, col);
event.preventDefault();
break;
default:
break;
}
};
const handleCellActivation = (row, col) => {
console.log(`Cell activated: [${row}, ${col}]`);
};
return (
<div
role='grid'
onKeyDown={handleKeyDown}
tabIndex={0}
style={{ outline: focusedCell ? '2px solid blue' : 'none' }}
>
<HeatMapComponent
id='heatmap'
dataSource={data}
cellRender={(args) => {
// Highlight focused cell
if (focusedCell && focusedCell.row === args.row && focusedCell.col === args.column) {
args.cellElement.style.outline = '3px solid blue';
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>
);
}Focus Indicators
<HeatMapComponent
id='heatmap'
dataSource={data}
cellRender={(args) => {
// Add clear focus indicator
const cellElement = args.cellElement;
// Default state
cellElement.style.outline = '1px solid transparent';
// On focus (keyboard navigation)
cellElement.onFocus = () => {
cellElement.style.outline = '3px solid #0066cc';
cellElement.style.outlineOffset = '2px';
};
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Screen Reader Support
ARIA Labels
<div role='main'>
<h1 id='heatmap-title'>Quarterly Sales Heatmap</h1>
<HeatMapComponent
id='heatmap'
dataSource={data}
titleSettings={{text: 'Quarterly Sales by Region'}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
<div aria-describedby='legend-description'>
<h2>Legend</h2>
<p id='legend-description'>
Blue represents low sales (0-25%), green represents medium sales (25-75%),
and red represents high sales (75-100%).
</p>
</div>
</div>Meaningful Tooltip Content
<HeatMapComponent
id='heatmap'
dataSource={data}
tooltipRender={(args) => {
// Create descriptive tooltip for screen readers
args.content = `
Region: ${args.content.row},
Quarter: ${args.content.column},
Sales: $${args.content.value}000
`;
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Data Table as Fallback
export function AccessibleDataPresentation() {
return (
<div>
<h1>Sales Data</h1>
{/* Heatmap for sighted users */}
<div role='img' aria-label='Sales data heatmap visualization'>
<HeatMapComponent id='heatmap' dataSource={data}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>
{/* Data table for screen reader users */}
<div role='region' aria-label='Data in table format'>
<h2>Sales Data Table</h2>
<table>
<caption>Quarterly sales data by region</caption>
<thead>
<tr>
<th>Region</th>
<th>Q1 ($000)</th>
<th>Q2 ($000)</th>
<th>Q3 ($000)</th>
</tr>
</thead>
<tbody>
{data.map((item, idx) => (
<tr key={idx}>
<td>{item.row}</td>
<td>{item.value}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
);
}Common Issues
| Issue | Cause | Solution |
|---|---|---|
| Heatmap not displaying | Missing data or container | Provide dataSource and ensure container has dimensions |
| Styles not applying | CSS not imported | Add import '@syncfusion/ej2-base/styles/material.css' |
| Axes labels overlap | Too many labels in small space | Rotate labels with labelRotation={45} |
| Poor performance | Large dataset with SVG mode | Use renderingMode='Canvas' for >1000 cells |
| Tooltips not showing | Tooltip service not injected | Add <Inject services={[Tooltip]} /> |
Troubleshooting Guide
Issue 1: HeatMap Not Rendering
Symptoms: Blank component, no error in console
Diagnosis:
// Check if dataSource is provided
if (!dataSource || dataSource.length === 0) {
console.error('No data provided');
}
// Check container dimensions
const container = document.getElementById('heatmap');
console.log('Container size:', {
width: container.offsetWidth,
height: container.offsetHeight
});Solution:
<div style={{ width: '800px', height: '600px' }}>
<HeatMapComponent
id='heatmap'
dataSource={data} // Must have data
width='100%'
height='100%'
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>Issue 2: Styles Not Applied
Symptoms: Default gray colors, not using custom palette
Diagnosis:
// Check if CSS is imported
try {
const style = document.querySelector('link[href*="material.css"]');
console.log('Theme CSS loaded:', !!style);
} catch(e) {
console.error('CSS import error');
}Solution:
// In your entry file (main.jsx or index.js)
import '@syncfusion/ej2-base/styles/material.css'; // Must be at top
import { HeatMapComponent } from '@syncfusion/ej2-react-heatmap';Issue 3: Axes Labels Overlapping
Symptoms: Labels stacked or unreadable
Solution:
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{
labels: longLabelList,
labelRotation: 45, // Rotate labels
labelIntersectAction: 'Rotate45' // Auto-rotate if needed
}}
yAxis={{
labels: longLabelList,
opposedPosition: false
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Issue 4: Large Dataset Performance
Symptoms: Slow rendering, browser lag with >5000 cells
Solution:
// Force Canvas rendering for large data
<HeatMapComponent
id='heatmap'
dataSource={largeData}
renderingMode='Canvas' // Not 'Auto'
showTooltip={false}
>
<Inject services={[Legend]} />
</HeatMapComponent>Issue 5: Tooltips Not Showing
Symptoms: Hover on cells, no tooltip appears
Diagnosis:
// Check if Tooltip service is injected
const heatmap = document.querySelector('.e-heatmap');
console.log('Has tooltip service:', heatmap.ej2_instances?.[0]?.tooltipModule);Solution:
import { Tooltip } from '@syncfusion/ej2-react-heatmap';
<HeatMapComponent id='heatmap' dataSource={data}>
<Inject services={[Legend, Tooltip]} /> // Add Tooltip
</HeatMapComponent>Migration from EJ1
EJ1 vs EJ2 Differences
| Feature | EJ1 | EJ2 |
|---|---|---|
| Package | @syncfusion/ej-react | @syncfusion/ej2-react-heatmap |
| Component | ejHeatMap | HeatMapComponent |
| Data binding | data property | dataSource property |
| Events | onCellClick | cellClick |
| Rendering | Auto | SVG/Canvas modes |
Basic Migration Example
EJ1 Code:
// Old EJ1 way
<EjHeatMap
dataSource={data}
onCellClick={handleClick}
/>EJ2 Code:
// New EJ2 way
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
<HeatMapComponent
dataSource={data}
cellClick={handleClick}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Data Format Migration
EJ1:
const data = [
[10, 20, 30],
[40, 50, 60]
];EJ2: (Same format works)
const data = [
[10, 20, 30],
[40, 50, 60]
];
// Or JSON format (EJ2 only)
const data = [
{ row: 'A', column: 'X', value: 10 },
{ row: 'A', column: 'Y', value: 20 }
];Event Name Changes
EJ1 → EJ2:
onCellClick→cellClickonCellMouseMove→cellMouseMoveonCellMouseLeave→cellMouseLeaveonCellSelection→cellSelected
Complete Migration Template
// Old EJ1 component
/*
<EjHeatMap
id='heatmap'
dataSource={data}
xAxis={{ labels: ['Q1', 'Q2'] }}
yAxis={{ labels: ['North', 'South'] }}
onCellClick={handleCellClick}
onCellMouseMove={handleMouseMove}
/>
*/
// New EJ2 component
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
import '@syncfusion/ej2-base/styles/material.css';
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{ labels: ['Q1', 'Q2'] }}
yAxis={{ labels: ['North', 'South'] }}
cellClick={handleCellClick}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Advanced Features & Events
Table of Contents
- Bubble HeatMap
- Creating a Bubble HeatMap
- Bubble Sizing Configuration
- Use Cases for Bubble HeatMaps
- Event Handling
- Core Events
- Created Event (Component Initialization)
- Multi-Event Handler
- Rendering Mode Switching
- Automatic Switching
- Manual Canvas Mode
- SVG Mode with Performance Tips
- Custom Cell Rendering
- Basic Cell Rendering
- Custom Icons/Emojis in Cells
- Complex Cell Rendering with Data Lookup
- Data Binding Events
- After Data Bind
- Dynamic Data Updates
- Performance Optimization
- Large Dataset Handling
- Lazy Loading Pattern
- Debounced Refresh
- Complete Advanced Example
Bubble HeatMap
Creating a Bubble HeatMap
A bubble heatmap combines cell color with bubble size for bivariate data visualization. There are several bubble types:
- Size: Bubble size varies with data, color is gradient
- Color: Bubble size is fixed, color varies with data
- Sector: Bubble sector angle represents data value
- SizeAndColor: Both bubble size and color vary with data
Array Binding with SizeAndColor Type
For array binding, use 2D arrays where each cell contains [colorValue, sizeValue]:
import { HeatMapComponent, Inject, Legend, Tooltip, Adaptor } from '@syncfusion/ej2-react-heatmap';
export function BubbleHeatmap() {
// Array of arrays: each cell is [value1, value2]
const data = [
[[4, 39], [3, 8], [1, 3], [1, 10]],
[[4, 28], [5, 92], [5, 73], [3, 1]],
[[4, 45], [5, 152], [0, 44], [4, 54]]
];
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{ labels: ['Year1', 'Year2', 'Year3'] }}
yAxis={{ labels: ['Q1', 'Q2', 'Q3', 'Q4'] }}
paletteSettings={{
palette: [
{ color: '#C06C84' },
{ color: '#6C5B7B' },
{ color: '#355C7D' }
],
type: 'Gradient'
}}
legendSettings={{ visible: true }}
cellSettings={{
tileType: 'Bubble',
bubbleType: 'SizeAndColor',
border: { width: 1 }
}}
showTooltip={true}
>
<Inject services={[Legend, Tooltip, Adaptor]} />
</HeatMapComponent>
);
}Bubble Size Type (Size Variation Only)
Use 2D array data with bubbleType: 'Size' for variable bubble sizes:
<HeatMapComponent
id='heatmap'
dataSource={[[73, 39, 26], [93, 58, 53], [54, 39, 26]]}
cellSettings={{
tileType: 'Bubble',
bubbleType: 'Size',
border: { width: 1 }
}}
paletteSettings={{
palette: [
{ color: '#C06C84' },
{ color: '#6C5B7B' },
{ color: '#355C7D' }
],
type: 'Gradient'
}}
legendSettings={{ visible: true }}
>
<Inject services={[Legend, Tooltip, Adaptor]} />
</HeatMapComponent>Bubble Color Type (Color Variation Only)
Use 2D array data with bubbleType: 'Color' for variable colors with fixed size:
<HeatMapComponent
id='heatmap'
dataSource={[[73, 39, 26], [93, 58, 53], [54, 39, 26]]}
cellSettings={{
tileType: 'Bubble',
bubbleType: 'Color',
border: { width: 1 }
}}
paletteSettings={{
palette: [
{ color: '#C06C84' },
{ color: '#6C5B7B' },
{ color: '#355C7D' }
],
type: 'Gradient'
}}
legendSettings={{ visible: true }}
>
<Inject services={[Legend, Tooltip, Adaptor]} />
</HeatMapComponent>Key Properties for Bubble HeatMaps
| Property | Type | Values | Description |
|---|---|---|---|
tileType | string | 'Rect' \ | 'Bubble' |
bubbleType | string | 'Size' \ | 'Color' \ |
bubbleSize | object | { minimum, maximum } | Bubble size range (for Size type) |
isInversedbubblesize | boolean | true \ | false |
showLabel | boolean | true \ | false |
Use Cases for Bubble HeatMaps
- Correlation with Intensity: Color = correlation strength, Bubble = frequency
- Financial Data: Color = return %, Size = volatility
- Network Analysis: Color = traffic volume, Size = node importance
- Aviation Safety: Color = fatalities, Size = accidents
- Scientific Data: Two dimensions of measurement combined
- Labor Force Analysis: Color = participation rate, Size = population
Custom Tooltip for Bubble Data
For SizeAndColor bubble maps, customize tooltip to show both values:
tooltipRender={(args) => {
if (args.value) {
args.content = [
'Category : ' + args.xLabel + '<br/>',
'Period : ' + args.yLabel + '<br/>',
'Value 1 (Bubble Size) : ' + args.value[0].bubbleData + '<br/>',
'Value 2 (Color) : ' + args.value[1].bubbleData
];
}
}}Event Handling
Core Events
<HeatMapComponent
id='heatmap'
dataSource={data}
created={(args) => {
console.log('HeatMap created successfully');
}}
cellClick={(args) => {
console.log(`Cell clicked: [${args.row}, ${args.column}] = ${args.value}`);
}}
cellSelected={(args) => {
console.log(`Cell selected: [${args.row}, ${args.column}]`);
}}
cellDoubleClick={(args) => {
console.log(`Cell double clicked: [${args.row}, ${args.column}]`);
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Created Event (Component Initialization)
import { useRef, useEffect } from 'react';
export function InitializationTracking() {
const heatmapRef = useRef(null);
const handleCreated = (args) => {
console.log('HeatMap initialization complete');
console.log('Axes:', {
xAxisLabels: heatmapRef.current.xAxis.labels,
yAxisLabels: heatmapRef.current.yAxis.labels
});
};
return (
<HeatMapComponent
ref={heatmapRef}
id='heatmap'
dataSource={data}
created={handleCreated}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Multi-Event Handler
import { useState } from 'react';
export function EventLogger() {
const [events, setEvents] = useState([]);
const logEvent = (eventName, details) => {
const timestamp = new Date().toLocaleTimeString();
setEvents(prev => [...prev.slice(-9), {
timestamp,
event: eventName,
details
}]);
};
return (
<div>
<HeatMapComponent
id='heatmap'
dataSource={data}
cellClick={(args) => {
logEvent('cellClick', `[${args.row}, ${args.column}]`);
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
<div style={{ marginTop: '20px', maxHeight: '200px', overflow: 'auto', border: '1px solid #ddd', padding: '10px' }}>
<h4>Event Log:</h4>
{events.map((e, idx) => (
<div key={idx} style={{ fontSize: '12px', color: '#666', marginBottom: '5px' }}>
[{e.timestamp}] {e.event}: {e.details}
</div>
))}
</div>
</div>
);
}Rendering Mode Switching
Automatic Switching
<HeatMapComponent
id='heatmap'
dataSource={largeData} // 1000+ cells
renderingMode='Auto' // Automatically chooses SVG or Canvas
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Auto behavior:
- < 1000 cells → SVG (better styling)
- ≥ 1000 cells → Canvas (better performance)
Manual Canvas Mode
<HeatMapComponent
id='heatmap'
dataSource={veryLargeData} // 10,000+ cells
renderingMode='Canvas' // Force Canvas for performance
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Canvas advantages:
- Handles 10,000+ cells efficiently
- Single bitmap rendering
- Lower memory usage
Canvas limitations:
- Less detailed cell styling
- No direct CSS for cells
- Use
cellRenderevent for customization
SVG Mode with Performance Tips
// For detailed styling with smaller datasets
<HeatMapComponent
id='heatmap'
dataSource={data} // < 500 cells for best performance
renderingMode='SVG'
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Custom Cell Rendering
Basic Cell Rendering
<HeatMapComponent
id='heatmap'
dataSource={data}
cellRender={(args) => {
// Modify cell content
args.displayText = args.value + '%';
// Conditional styling
if (args.value > 80) {
args.cellElement.style.fontWeight = 'bold';
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Custom Icons/Emojis in Cells
export function IconHeatmap() {
const statusMap = {
100: '✓✓', // Excellent
75: '✓', // Good
50: '~', // Fair
25: '✗' // Poor
};
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
cellRender={(args: ICellEventArgs) => {
let icon = '?';
if (typeof args.value === 'number') {
for (const [thresholdStr, symbol] of Object.entries(statusMap)) {
const threshold = Number(thresholdStr);
if (args.value >= threshold) {
icon = symbol as string;
break;
}
}
}
args.displayText = icon;
args.heatmap.cellSettings.textStyle.size = '20px'
args.heatmap.cellSettings.textStyle.textAlignment = 'Center'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Complex Cell Rendering with Data Lookup
export function DataLookupHeatmap() {
const data = [
{ row: 'Product A', column: 'Q1', value: 150, trend: 'up' },
{ row: 'Product A', column: 'Q2', value: 200, trend: 'up' },
{ row: 'Product B', column: 'Q1', value: 100, trend: 'down' }
];
const trendIcons = { up: '📈', down: '📉', flat: '→' };
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
cellRender={(args) => {
// Find the data item for this cell
const item = data.find(d =>
d.row === args.row && d.column === args.column
);
if (item) {
const icon = trendIcons[item.trend];
args.displayText = `${icon} ${item.value}`;
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Data Binding Events
After Data Bind
<HeatMapComponent
id='heatmap'
dataSource={data}
load={(args) => {
console.log('Data loaded successfully');
// Perform post-load operations
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Dynamic Data Updates
import { useState, useRef } from 'react';
export function DynamicDataHeatmap() {
const [data, setData] = useState(initialData);
const heatmapRef = useRef(null);
const updateData = (newData) => {
setData(newData);
if (heatmapRef.current) {
// Refresh heatmap with new data
heatmapRef.current.refresh();
}
};
const handleRealTimeUpdate = () => {
const updated = data.map(item => ({
...item,
value: Math.floor(Math.random() * 100)
}));
updateData(updated);
};
return (
<div>
<button onClick={handleRealTimeUpdate}>Refresh Data</button>
<HeatMapComponent
ref={heatmapRef}
id='heatmap'
dataSource={data}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>
);
}Performance Optimization
Large Dataset Handling
export function OptimizedLargeHeatmap() {
// Generate 10,000 cells
const largeData = Array.from({ length: 100 }, (_, i) =>
Array.from({ length: 100 }, () => Math.floor(Math.random() * 100))
);
return (
<HeatMapComponent
id='heatmap'
dataSource={largeData}
renderingMode='Canvas' // Use Canvas, not SVG
showTooltip = {false}
legendSettings={{
visible: true // Keep legend
}}
>
<Inject services={[Legend]} />
</HeatMapComponent>
);
}Lazy Loading Pattern
import { useState, useEffect } from 'react';
export function LazyLoadHeatmap() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate async data loading
const timer = setTimeout(() => {
setData(generateData());
setLoading(false);
}, 1000);
return () => clearTimeout(timer);
}, []);
if (loading) {
return <div>Loading heatmap...</div>;
}
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
renderingMode='Canvas'
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}
function generateData() {
const rows = 50;
const cols = 50;
const data = [];
for (let i = 0; i < rows; i++) {
const row = [];
for (let j = 0; j < cols; j++) {
row.push(Math.floor(Math.random() * 100));
}
data.push(row);
}
return data;
}Debounced Refresh
import { useRef } from 'react';
export function DebouncedHeatmap() {
const heatmapRef = useRef(null);
const refreshTimeoutRef = useRef(null);
const handleDataChange = (newData) => {
// Clear previous timeout
if (refreshTimeoutRef.current) {
clearTimeout(refreshTimeoutRef.current);
}
// Debounce refresh by 500ms
refreshTimeoutRef.current = setTimeout(() => {
if (heatmapRef.current) {
heatmapRef.current.dataSource = newData;
heatmapRef.current.refresh();
}
}, 500);
};
return (
<HeatMapComponent
ref={heatmapRef}
id='heatmap'
dataSource={data}
renderingMode='Canvas'
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Complete Advanced Example
import { useRef, useState, useEffect } from 'react';
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
export function AdvancedHeatmap() {
const heatmapRef = useRef(null);
const [stats, setStats] = useState({
cellsRendered: 0,
renderTime: 0,
eventCount: 0
});
const largeData = generateMatrixData(100, 100);
useEffect(() => {
const startTime = performance.now();
return () => {
const endTime = performance.now();
setStats(prev => ({
...prev,
renderTime: (endTime - startTime).toFixed(2)
}));
};
}, []);
const handleCellClick = (args) => {
setStats(prev => ({
...prev,
eventCount: prev.eventCount + 1
}));
};
return (
<div>
<div style={{ marginBottom: '20px', padding: '10px', background: '#f0f0f0' }}>
<h3>Performance Stats</h3>
<p>Render Time: {stats.renderTime}ms</p>
<p>Events Handled: {stats.eventCount}</p>
</div>
<HeatMapComponent
ref={heatmapRef}
id='heatmap'
dataSource={largeData}
renderingMode='Canvas'
cellClick={handleCellClick}
cellRender={(args) => {
if (args.value > 75) {
args.displayText = '●';
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>
);
}
function generateMatrixData(rows, cols) {
const data = [];
for (let i = 0; i < rows * cols; i++) {
data.push(Math.floor(Math.random() * 100));
}
return data;
}HeatMap API Reference
This document summarizes the primary component props, methods, events and commonly used nested models for the Syncfusion React HeatMap (HeatMapComponent) based on the official API.
Component Summary
- Package:
@syncfusion/ej2-react-heatmap - Component API: https://ej2.syncfusion.com/react/documentation/api/heatmap/index-default
- Component tag:
HeatMapComponent
Key Props (common)
dataSource(Array|Object) — 2D array or data object for cells. Example:[[1,2],[3,4]].xAxis(AxisModel) — column axis configuration (labels,valueType,interval,labelFormat).yAxis(AxisModel) — row axis configuration (labels,valueType).cellSettings(CellSettingsModel) — controls cell rendering:showLabel,border,format,enableCellHighlight.paletteSettings(PaletteSettingsModel) — color palette and ranges for values.legendSettings(LegendSettingsModel) — legend visibility, position, width, format.tooltipSettings(TooltipSettingsModel) — control tooltip enablement and format.titleSettings(TitleModel) — title text, alignment, and style.margin(MarginModel) — spacing around the chart:left,right,top,bottom.renderingMode(DrawType) — rendering engine:'SVG'(default) or'Canvas'(useful for very large datasets).showTooltip(boolean) — enable/disable tooltips.enableHtmlSanitizer(boolean) — sanitize returned HTML in labels/tooltips when enabled.enablePersistence(boolean) — persist component state across reloads.enableRtl(boolean) — enable right-to-left layout.height/width(string) — component dimensions (e.g.,'400px','100%').
Important Methods
- Full methods reference: https://ej2.syncfusion.com/react/documentation/api/heatmap/index-default#methods
clearSelection()— clears any selected cells.destroy()— clean up the component and detach events.export(type, fileName, orientation?)— export the heatmap asPNG|JPEG|SVG|PDF(type string), optionalfileNameand PDForientation.print()— print the heatmap.refresh()— re-render the component after programmatic changes.
Events
cellClick(ICellClickEventArgs) — fired when a cell is clicked. Common args:rowIndex,columnIndex,value,cell,x,y.cellDoubleClick(ICellClickEventArgs) — fired on double-click.cellRender(ICellEventArgs) — called per-cell during rendering; allow customizingdisplayTextor cell styles.cellSelected(ISelectedEventArgs) — fired when selection changes.legendRender(ILegendRenderEventArgs) — legend item rendering hook.load/loaded(ILoadedEventArgs) — lifecycle events during load/after load.resized(IResizeEventArgs) — after component is resized.tooltipRender(ITooltipEventArgs) — customize tooltip content/format before shown.created— called after component initialization.
Common Nested Models (short)
- CellSettingsModel
showLabel(boolean) — show cell labelsformat(string) — format string for display textborder({ width:number, color:string }) — cell border
- LegendSettingsModel
visible(boolean)position(string) —'Top'|'Bottom'|'Left'|'Right'width(string|number)
- PaletteSettingsModel
palette(Array) — entries:{ value, color }or range objectstype(string) —'Gradient'|'Fixed'
- AxisModel (xAxis / yAxis)
labels(Array) — explicit labels for categoriesvalueType(string) —'Numeric'|'Category'|'DateTime'labelFormat(string) — formatting for labels
- TooltipSettingsModel
visible(boolean)format(string) — tooltip display format
Example Snippet (props + events)
<HeatMapComponent
id="heatmap"
dataSource={data}
xAxis={{ labels: ['A','B','C'] }}
yAxis={{ labels: ['X','Y'] }}
cellSettings={{ showLabel: true, border: { width: 1, color: '#fff' } }}
legendSettings={{ visible: true, position: 'Bottom' }}
paletteSettings={{ palette: [{ value: 0, color: '#eef' }, { value: 100, color: '#c33' }], type: 'Gradient' }}
renderingMode="Canvas"
cellClick={(args) => console.log('Cell:', args)}
cellRender={(args) => { args.displayText = args.value + '%'; }}
created={() => console.log('created')}
>
<Inject services={[Legend, Tooltip, Adaptor]} />
</HeatMapComponent>Notes & Tips
- For very large data sets prefer
renderingMode='Canvas'for performance. - Use
cellRenderto customize displayed labels without altering data. export()supports common raster/vector formats; pass'PDF'with orientation when needed.
For the authoritative, full API (every prop, event, model and types), refer to the official Syncfusion documentation: https://ej2.syncfusion.com/react/documentation/api/heatmap/index-default
Axes Configuration
Table of Contents
- Axis Types
- Numerical Axis
- Basic Numerical Axis
- Numerical Axis with Custom Intervals
- Use Case: Temperature Range
- Categorical Axis
- Basic Categorical Axis
- Categorical Axis with JSON Data
- Use Case: Sales by Product and Month
- DateTime Axis
- Basic DateTime Axis
- DateTime with Hourly Data
- DateTime Format Options
- Axis Properties
- Common Axis Properties
- Advanced Positioning
- Inverted Axes
- Opposed Position
- Rotated Labels
- Labels and Formatting
- Custom Label Styling
- Common Axis Configuration Patterns
- Pattern 1: Time Series with Monthly Data
- Pattern 2: Performance Matrix with Inversed Y-Axis
- Pattern 3: Multi-Dimensional Data with Numeric Range
Axis Types
HeatMap supports three axis types, each suited for different data scenarios:
| Axis Type | Use Case | Example |
|---|---|---|
| Numerical | Continuous numeric ranges | Temperature (0-100), Score (0-1000) |
| Categorical | Discrete labels/categories | Months, Regions, Products |
| DateTime | Time-based data | Dates, Hours, Timestamps |
Numerical Axis
Basic Numerical Axis
<HeatMapComponent id='heatmap'
xAxis={{
valueType: 'Numeric',
minimum: 0,
maximum: 100,
}}
yAxis ={{
valueType: 'Numeric',
minimum: 0,
maximum: 100,
}}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Numerical Axis with Custom Intervals
<HeatMapComponent id='heatmap' dataSource={data}
xAxis={{
valueType: 'Numeric',
minimum: 0,
maximum: 100,
interval: 10, // Label every 10 units
labels: ['0', '10', '20', '30', '40', '50', '60', '70', '80', '90', '100']
}}
yAxis={{
valueType: 'Numeric',
minimum: 0,
maximum: 50,
interval: 5,
}}>>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Use Case: Temperature Range
// Temperature data from 0°C to 40°C
const temperatureData = [
[5, 15, 25, 35],
[8, 18, 28, 38],
[10, 20, 30, 40]
];
<HeatMapComponent
id='heatmap'
dataSource={temperatureData}
xAxis={{
valueType: 'Numeric',
minimum: 0,
maximum: 40,
interval: 10,
title: { text: 'Temperature (°C)' }
}}
yAxis={{
valueType: 'Numeric',
minimum: 0,
maximum: 3,
title: { text: 'Time Period' }
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Categorical Axis
Basic Categorical Axis
Categorical axes use explicit labels for each row/column:
const data = [
[73, 39, 26, 39],
[93, 58, 53, 38],
[54, 39, 26, 40]
];
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{
valueType: 'Category',
labels: ['Q1', 'Q2', 'Q3', 'Q4']
}}
yAxis={{
valueType: 'Category',
labels: ['North Region', 'South Region', 'East Region']
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Categorical Axis with JSON Data
const data = [
{ row: 'Product A', column: 'Jan', value: 150 },
{ row: 'Product A', column: 'Feb', value: 120 },
{ row: 'Product A', column: 'Mar', value: 180 },
{ row: 'Product B', column: 'Jan', value: 200 },
{ row: 'Product B', column: 'Feb', value: 190 },
{ row: 'Product B', column: 'Mar', value: 220 }
];
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{
valueType: 'Category'
}}
yAxis={{
valueType: 'Category',
}}
dataSourceSettings={{ xDataMapping: 'column', yDataMapping: 'row', valueMapping: 'value' }}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Benefits:
- Automatically extracts unique labels from data
- Maintains correspondence with data rows/columns
- No manual label management
Use Case: Sales by Product and Month
const salesData = [
{ row: 'Laptop', column: 'January', value: 450 },
{ row: 'Laptop', column: 'February', value: 520 },
{ row: 'Laptop', column: 'March', value: 480 },
{ row: 'Monitor', column: 'January', value: 320 },
{ row: 'Monitor', column: 'February', value: 380 },
{ row: 'Monitor', column: 'March', value: 410 },
{ row: 'Keyboard', column: 'January', value: 280 },
{ row: 'Keyboard', column: 'February', value: 300 },
{ row: 'Keyboard', column: 'March', value: 350 }
];
<HeatMapComponent
id='heatmap'
dataSource={salesData}
dataSourceSettings={{ xDataMapping: 'column', yDataMapping: 'row', valueMapping: 'value' }}
xAxis={{
valueType: 'Category'
}}
yAxis={{
valueType: 'Category'
}}
title={{ text: 'Monthly Sales by Product' }}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>DateTime Axis
Basic DateTime Axis
const datetimeData = [
{
row: 'Server 1',
column: new Date(2024, 0, 1),
value: 75
},
{
row: 'Server 1',
column: new Date(2024, 0, 2),
value: 82
},
// More data...
];
<HeatMapComponent
id='heatmap'
dataSource={datetimeData}
dataSourceSettings={{xDataMapping: 'column', yDataMapping: 'row', valueMapping: 'value'}}
xAxis={{
valueType: 'DateTime',
labelFormat: 'M/d' // MM/dd format
}}
yAxis={{
valueType: 'Category'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>DateTime with Hourly Data
const hourlyData = [];
const startDate = new Date(2024, 0, 1);
for (let hour = 0; hour < 24; hour++) {
const date = new Date(startDate);
date.setHours(hour);
hourlyData.push({
row: 'CPU Usage',
column: date,
value: Math.floor(Math.random() * 100)
});
}
<HeatMapComponent
id='heatmap'
dataSource={hourlyData}
dataSourceSettings={{ xDataMapping: 'column', yDataMapping: 'row', valueMapping: 'value' }}
xAxis={{
valueType: 'DateTime',
labelFormat: 'h:mm tt' // 12-hour format with AM/PM
}}
yAxis={{
valueType: 'Category'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>DateTime Format Options
// Common DateTime label formats:
labelFormat: 'M/d' // 1/1, 1/2, etc.
labelFormat: 'M/d/y' // 1/1/24
labelFormat: 'MMM' // Jan, Feb, Mar
labelFormat: 'MMMM' // January, February
labelFormat: 'ddd' // Mon, Tue, Wed
labelFormat: 'dddd' // Monday, Tuesday
labelFormat: 'h:mm tt' // 1:30 PM
labelFormat: 'HH:mm' // 13:30 (24-hour)
labelFormat: 'M/d h:mm tt' // 1/1 1:30 PMAxis Properties
Common Axis Properties
<HeatMapComponent id='heatmap' dataSource={data}
xAxis={{
valueType: 'Category',
labels: ['A', 'B', 'C'],
// Title and labels
title: {
text: 'Column Headers',
textStyle: { size: '14px' }
},
// Appearance
labelRotation: 45, // Rotate labels
isInversed: false, // Reverse order?
opposedPosition: false, // Position opposite side?
// Intervals
labelIntersectAction: 'Rotate45' // 'Hide' or 'Rotate'
}}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Advanced Positioning
Inverted Axes
Reverse the order of axis labels:
<HeatMapComponent id='heatmap' dataSource={data}
xAxis={{
valueType: 'Category',
labels: ['A', 'B', 'C', 'D'],
isInversed: true // Labels now: D, C, B, A
}}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Opposed Position
Place axis on opposite side (right for X, top for Y):
<HeatMapComponent id='heatmap' dataSource={data}
xAxis={{
opposedPosition: true, // X-axis at top
valueType: 'Category',
labels: ['Q1', 'Q2', 'Q3', 'Q4']
}}
yAxis={{
opposedPosition: true, // Y-axis at right
valueType: 'Category',
labels: ['North', 'South', 'East', 'West']
}}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Rotated Labels
<HeatMapComponent id='heatmap' dataSource={data}
xAxis={{
labelRotation: 45, // Rotate 45 degrees
labels: ['Very Long Column Header 1', 'Very Long Column Header 2']
}}>
</HeatMapComponent>Labels and Formatting
Custom Label Styling
<HeatMapComponent id='heatmap' dataSource={data}
xAxis={{
labels: ['Jan', 'Feb', 'Mar', 'Apr'],
textStyle: {
size: '12px',
color: '#333',
fontWeight: 'bold'
},
title: {
text: 'Months',
textStyle: {
size: '14px',
color: '#666'
}
}
}}
>
</HeatMapComponent>Common Axis Configuration Patterns
Pattern 1: Time Series with Monthly Data
const monthlyData = generateMonthlyData();
<HeatMapComponent
id='heatmap'
dataSource={monthlyData}
dataSourceSettings={{ xDataMapping: 'month', yDataMapping: 'metric', valueMapping: 'Category' }}
xAxis={{
valueType: 'DateTime',
labelFormat: 'MMM yyyy'
}}
yAxis={{
valueType: 'Category'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Pattern 2: Performance Matrix with Inversed Y-Axis
// High performance at top, low at bottom
<HeatMapComponent
id='heatmap'
dataSource={performanceData}
xAxis={{
valueType: 'Category',
labels: ['CPU', 'Memory', 'Disk', 'Network'],
title: { text: 'System Resources' }
}}
yAxis={{
valueType: 'Category',
labels: ['Server 1', 'Server 2', 'Server 3'],
isInversed: true,, // Reverse to show best at top
title: { text: 'Servers' }
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Pattern 3: Multi-Dimensional Data with Numeric Range
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{
valueType: 'Numeric',
minimum: 0,
maximum: 100,
interval: 20
}}
yAxis={{
valueType: 'Category',
labels: generateLabels()
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Data Binding & Setup
Table of Contents
- Data Formats
- 2D Array Binding
- Basic 2D Array
- 2D Array with React Hooks
- JSON Data Binding
- Basic JSON Format
- JSON with Additional Properties
- Dynamic Data Loading
- Fetching from API
- Real-time Data Updates
- Data Transformation
- Filtering Data
- Normalizing Values (0-100 scale)
- Grouping and Aggregating
- Working with Large Datasets
- Canvas Rendering Mode (for >1000 cells)
- Limiting Visible Cells
- Pagination Pattern
- Best Practices
Data Formats
The HeatMap component supports two primary data formats:
1. 2D Array - Simple numeric arrays (recommended for simple data) 2. JSON Array - Object-based format with flexibility (recommended for labeled data)
2D Array Binding
Basic 2D Array
The simplest format: a JavaScript array of arrays where each inner array represents a row.
const data = [
[10, 20, 30, 40],
[50, 60, 70, 80],
[90, 100, 110, 120]
];
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{ labels: ['Jan', 'Feb', 'Mar', 'Apr'] }}
yAxis={{ labels: ['North', 'South', 'East'] }}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Characteristics:
- 3 rows × 4 columns
- Values automatically colored based on range
- X-axis labels correspond to columns
- Y-axis labels correspond to rows
2D Array with React Hooks
import { useState, useEffect } from 'react';
export function App() {
const [data, setData] = useState([]);
useEffect(() => {
// Initialize data
const initialData = [
[73, 39, 26],
[93, 58, 53],
[54, 39, 26]
];
setData(initialData);
}, []);
return (
<HeatMapComponent id='heatmap' dataSource={data}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}JSON Data Binding
Basic JSON Format
For more structured data with explicit row/column identifiers:
const data = [
{ 'row': 'North', 'column': 'Jan', 'value': 73 },
{ 'row': 'North', 'column': 'Feb', 'value': 39 },
{ 'row': 'North', 'column': 'Mar', 'value': 26 },
{ 'row': 'South', 'column': 'Jan', 'value': 93 },
{ 'row': 'South', 'column': 'Feb', 'value': 58 },
{ 'row': 'South', 'column': 'Mar', 'value': 53 }
];
<HeatMapComponent
id='heatmap'
dataSource={data}
dataSourceSettings={{ xDataMapping: 'column', yDataMapping: 'row', valueMapping: 'value' }}
xAxis={{ valueType: 'Category' }}
yAxis={{ valueType: 'Category' }}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Benefits:
- Self-documenting data structure
- Flexible data shapes (not limited to rectangular grids)
- Easy to filter, sort, or transform
- Better for sparse data
JSON with Additional Properties
const data = [
{
row: 'Product A',
column: 'Q1',
value: 150,
category: 'Electronics',
status: 'growth'
},
{
row: 'Product B',
column: 'Q1',
value: 80,
category: 'Electronics',
status: 'stable'
},
// More records...
];
<HeatMapComponent
id='heatmap'
dataSource={data}
dataSourceSettings={{ xDataMapping: 'column', yDataMapping: 'row', valueMapping: 'value' }}
xAxis={{ valueType: 'Category' }}
yAxis={{ valueType: 'Category' }}
cellRender={(args) => {
// Access custom properties
const status = data.find(d =>
d.row === args.row && d.column === args.column
)?.status;
if (status === 'growth') {
args.displayText = '📈 ' + args.value;
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Dynamic Data Loading
Fetching from API
import { useState, useEffect } from 'react';
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
export function App() {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Fetch data from API
fetch('/api/heatmap-data')
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
console.error('Error loading data:', error);
setLoading(false);
});
}, []);
if (loading) {
return <div>Loading heatmap...</div>;
}
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{ type: 'Category' }}
yAxis={{ type: 'Category' }}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Real-time Data Updates
import { useEffect, useRef } from 'react';
export function App() {
const heatmapRef = useRef(null);
useEffect(() => {
// Simulate real-time updates every 5 seconds
const interval = setInterval(() => {
const newData = generateRandomData();
if (heatmapRef.current) {
heatmapRef.current.dataSource = newData;
}
}, 5000);
return () => clearInterval(interval);
}, []);
function generateRandomData() {
const rows = 5;
const cols = 5;
const data = [];
for (let i = 0; i < rows * cols; i++) {
data.push(Math.floor(Math.random() * 100));
}
return data;
}
return (
<HeatMapComponent
ref={heatmapRef}
id='heatmap'
dataSource={generateRandomData()}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Data Transformation
Filtering Data
// Only show high-value cells
const rawData = [
{ row: 'A', column: 'X', value: 150 },
{ row: 'A', column: 'Y', value: 50 },
{ row: 'B', column: 'X', value: 200 },
{ row: 'B', column: 'Y', value: 30 }
];
const filteredData = rawData.filter(d => d.value > 75);
// Result: [{ row: 'A', column: 'X', value: 150 }, { row: 'B', column: 'X', value: 200 }]
<HeatMapComponent id='heatmap' dataSource={filteredData} />Normalizing Values (0-100 scale)
function normalizeData(data, min = 0, max = 100) {
const values = data.map(d => d.value);
const dataMin = Math.min(...values);
const dataMax = Math.max(...values);
const range = dataMax - dataMin;
return data.map(d => ({
...d,
value: ((d.value - dataMin) / range) * (max - min) + min
}));
}
const data = [
{ row: 'A', column: 'X', value: 1000 },
{ row: 'A', column: 'Y', value: 5000 }
];
const normalized = normalizeData(data);
// Values now between 0-100 for consistent color scalingGrouping and Aggregating
// Group by category and sum values
function aggregateData(data) {
const grouped = {};
data.forEach(item => {
const key = `${item.row}-${item.column}`;
if (!grouped[key]) {
grouped[key] = { ...item };
} else {
grouped[key].value += item.value;
}
});
return Object.values(grouped);
}
const rawData = [
{ row: 'Q1', column: 'Region A', value: 50 },
{ row: 'Q1', column: 'Region A', value: 30 }, // Duplicate
{ row: 'Q1', column: 'Region B', value: 75 }
];
const aggregated = aggregateData(rawData);
// Q1-Region A now has combined value: 80Working with Large Datasets
Canvas Rendering Mode (for >1000 cells)
<HeatMapComponent
id='heatmap'
dataSource={largeData}
renderingMode='Canvas' // Switch to Canvas for performance
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Why Canvas?
- SVG creates DOM elements for each cell (slow with large data)
- Canvas renders to bitmap (efficient with large data)
- Automatic switching based on data size
Limiting Visible Cells
// Only display a subset of data
const allData = generateLargeDataset(); // 1000+ rows
const visibleData = allData.slice(0, 100); // Show first 100
<HeatMapComponent
id='heatmap'
dataSource={visibleData}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Pagination Pattern
import { useState } from 'react';
export function PaginatedHeatmap() {
const [page, setPage] = useState(0);
const pageSize = 50;
const allData = generateLargeDataset();
const visibleData = allData.slice(
page * pageSize,
(page + 1) * pageSize
);
return (
<div>
<HeatMapComponent id='heatmap' dataSource={visibleData} />
<button onClick={() => setPage(page + 1)}>Next Page</button>
<button onClick={() => setPage(page - 1)} disabled={page === 0}>
Previous Page
</button>
</div>
);
}Best Practices
1. Choose the right format:
- Use 2D arrays for simple, rectangular data
- Use JSON for complex, labeled data
2. Keep data clean:
- Validate values before binding
- Handle missing/null values explicitly
3. Performance considerations:
- Use Canvas rendering for >1000 cells
- Implement pagination for very large datasets
- Update data references (not mutations) for React reactivity
4. Data updates:
- Always create new references when data changes
- Avoid mutating data arrays directly
- Use state management for complex data flows
Getting Started with React HeatMap Chart
Table of Contents
- Dependencies
- Installation
- Step 1: Install the HeatMap Package
- Step 2: Install Required Peer Dependencies (if not already installed)
- Project Setup
- Option A: Using Vite (Recommended - Faster Development)
- Option B: Using Create React App
- Adding to Your Project
- Step 1: Import Theme CSS
- Step 2: Import HeatMap Component
- Basic Implementation
- Minimal Example (Empty HeatMap)
- Complete Basic Example with Data
- CSS Import Pattern
- Running the Application
- For Vite
- For Create React App
- Troubleshooting
- Next Steps
Dependencies
The HeatMap component requires the following npm packages:
@syncfusion/ej2-react-heatmap
├── @syncfusion/ej2-heatmap (core library)
├── @syncfusion/ej2-base
├── @syncfusion/ej2-data
├── @syncfusion/ej2-svg-base
└── @syncfusion/ej2-react-baseThese are installed automatically when you add @syncfusion/ej2-react-heatmap.
Installation
Step 1: Install the HeatMap Package
npm install @syncfusion/ej2-react-heatmap --saveStep 2: Install Required Peer Dependencies (if not already installed)
npm install @syncfusion/ej2-react-base --saveProject Setup
Option A: Using Vite (Recommended - Faster Development)
Create a new Vite React project:
npm create vite@latest my-heatmap-app -- --template react
cd my-heatmap-app
npm installFor TypeScript support:
npm create vite@latest my-heatmap-app -- --template react-ts
cd my-heatmap-app
npm installOption B: Using Create React App
npx create-react-app my-heatmap-app
cd my-heatmap-appThen install HeatMap:
npm install @syncfusion/ej2-react-heatmap --saveAdding to Your Project
Step 1: Import Theme CSS
Add the Syncfusion theme CSS to your application entry point.
For Vite (in `src/main.jsx` or `src/main.tsx`):
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import '@syncfusion/ej2-base/styles/material.css'
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)For Create React App (in `src/index.js`):
import '@syncfusion/ej2-base/styles/material.css';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);Available Themes:
material.css(Material Design)bootstrap5.css(Bootstrap 5)fabric.css(Fluent Design)tailwind.css(Tailwind CSS)fluent2.css(Fluent 2)
Choose one theme based on your design preference.
Step 2: Import HeatMap Component
In your component file (e.g., App.jsx):
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';Basic Implementation
Minimal Example (Empty HeatMap)
import * as React from 'react';
import { HeatMapComponent } from '@syncfusion/ej2-react-heatmap';
import '@syncfusion/ej2-base/styles/material.css';
export function App() {
return (
<div>
<h1>HeatMap Example</h1>
<HeatMapComponent id='heatmap'></HeatMapComponent>
</div>
);
}
export default App;Complete Basic Example with Data
import * as React from 'react';
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
import '@syncfusion/ej2-base/styles/material.css';
export function App() {
const data = [
[73, 39, 26, 39, 94],
[93, 58, 53, 38, 26],
[54, 39, 26, 40, 42]
];
return (
<div style={{ padding: '20px' }}>
<h1>Sales Performance HeatMap</h1>
<HeatMapComponent
id='heatmap'
dataSource={data}
xAxis={{
labels: ['Q1', 'Q2', 'Q3', 'Q4', 'Q5']
}}
yAxis={{
labels: ['Region A', 'Region B', 'Region C']
}}
title={{ text: 'Sales Data Across Regions' }}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>
);
}
export default App;What's happening:
data: 2D array with 3 rows and 5 columnsxAxis.labels: Column headers (quarters)yAxis.labels: Row headers (regions)<Inject services={[Legend, Tooltip]} />: Enables legend and tooltipstitle: Adds a descriptive title to the heatmap
CSS Import Pattern
// At the top of your file, after other imports
import '@syncfusion/ej2-base/styles/material.css';
// Components don't need individual CSS imports
// The base theme CSS handles all Syncfusion componentsRunning the Application
For Vite:
npm run devThe application opens at http://localhost:5173 by default.
For Create React App:
npm startThe application opens at http://localhost:3000 by default.
Troubleshooting
Issue: Styles not appearing or component looks unstyled
- Solution: Make sure you've imported the CSS file (
material.cssor your chosen theme) at the top of your entry point before rendering components.
Issue: HeatMapComponent not found error
- Solution: Verify the import is correct:
import { HeatMapComponent } from '@syncfusion/ej2-react-heatmap';Issue: Blank heatmap with no data
- Solution: Provide a
dataSourceprop with 2D array data or JSON format data.
Issue: Dependency errors
- Solution: Run
npm installagain or clear node_modules:
rm -rf node_modules package-lock.json
npm installNext Steps
Once your basic setup is complete: 1. Learn about data formats → Read data-binding.md 2. Configure axes → Read axes-configuration.md 3. Customize appearance → Read legend-and-appearance.md 4. Add interaction → Read interaction-and-selection.md
Interaction & Selection
Table of Contents
- Selection Modes
- Single Cell Selection
- Selection
- No Selection
- Cell Selection Handler
- Track Selected Cell
- Get Row/Column Labels
- Highlighting Patterns
- Highlight Selected Cell
- Highlight Row/Column Group
- Custom Highlight Color
- Tooltip Configuration
- Enable Tooltips
- Disable Tooltips
- Custom Tooltip Format
- Advanced Tooltip Customization
- Tooltip Styling
- Mouse Events
- Cell Click Event
- Cell Mouse Hover
- Interactive Patterns
- Pattern 1: Click to Filter Data
- Pattern 2: Double-Click to Edit
- Pattern 3: Drill-Down Navigation
- Pattern 4: Export Selected Data
Selection Modes
Single Cell Selection
<HeatMapComponent
id='heatmap'
dataSource={data}
cellSelected={(args) => {
console.log(`Selected: [${args.row}, ${args.column}] = ${args.value}`);
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Users can click any cell; the cellSelected event fires with cell information.
Selection
<HeatMapComponent
id='heatmap'
dataSource={data}
allowSelection={true}
cellSelected={(args) => {
console.log(`Column ${args.column} selected`);
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>No Selection
<HeatMapComponent
id='heatmap'
dataSource={data}
allowSelection={false} // Disable selection
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Cell Selection Handler
Track Selected Cell
import { useState } from 'react';
export function SelectionTracker() {
const [selectedCell, setSelectedCell] = useState(null);
const handleCellSelection = (args) => {
setSelectedCell({
row: args.row,
column: args.column,
value: args.value
});
};
return (
<div>
<HeatMapComponent
id='heatmap'
dataSource={data}
cellSelected={handleCellSelection}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
{selectedCell && (
<div style={{ marginTop: '20px', padding: '10px', border: '1px solid #ddd' }}>
<h3>Selected Cell Info</h3>
<p>Row: {selectedCell.row}</p>
<p>Column: {selectedCell.column}</p>
<p>Value: {selectedCell.value}</p>
</div>
)}
</div>
);
}Get Row/Column Labels
import { useRef } from 'react';
export function LabeledSelection() {
const heatmapRef = useRef(null);
const handleCellSelection = (args) => {
const heatmap = heatmapRef.current;
// Get axis labels
const xLabel = heatmap.xAxis.labels[args.column];
const yLabel = heatmap.yAxis.labels[args.row];
console.log(`Selected: ${yLabel} (${xLabel}) = ${args.value}`);
};
return (
<HeatMapComponent
ref={heatmapRef}
id='heatmap'
dataSource={data}
xAxis={{ labels: ['Q1', 'Q2', 'Q3', 'Q4'] }}
yAxis={{ labels: ['Region A', 'Region B', 'Region C'] }}
cellSelected={handleCellSelection}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Highlighting Patterns
Highlight Selected Cell
import { useState } from 'react';
export function HighlightedSelection() {
const [highlighted, setHighlighted] = useState(null);
const handleCellSelection = (args) => {
setHighlighted({
row: args.row,
column: args.column
});
};
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
cellSelected={handleCellSelection}
cellRender={(args) => {
// Add highlight styling
if (highlighted &&
highlighted.row === args.row &&
highlighted.column === args.column) {
args.cellElement.style.border = '3px solid black';
args.cellElement.style.boxShadow = '0 0 8px rgba(0, 0, 0, 0.5)';
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Highlight Row/Column Group
export function GroupHighlight() {
const [selectedRow, setSelectedRow] = useState(null);
const handleCellSelection = (args) => {
setSelectedRow(args.row);
};
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
cellSelected={handleCellSelection}
cellRender={(args) => {
// Highlight entire row if row selected
if (selectedRow === args.row) {
args.cellElement.style.opacity = '1';
args.cellElement.style.borderWidth = '2px';
} else {
args.cellElement.style.opacity = '0.5'; // Dim other rows
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Custom Highlight Color
<HeatMapComponent
id='heatmap'
dataSource={data}
cellRender={(args) => {
// Custom highlight for high values
if (args.value > 80) {
args.cellElement.style.boxShadow = 'inset 0 0 0 2px #ff6b6b';
args.cellElement.style.fontWeight = 'bold';
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Tooltip Configuration
Enable Tooltips
import { Tooltip } from '@syncfusion/ej2-react-heatmap';
<HeatMapComponent id='heatmap' dataSource={data}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Tooltips show by default on cell hover.
Disable Tooltips
<HeatMapComponent
id='heatmap'
dataSource={data}
showTooltip={false}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Custom Tooltip Format
<HeatMapComponent
id='heatmap'
dataSource={data}
tooltipSettings={{
template: 'Value: ${value}' // ${value}, ${row}, ${column}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Advanced Tooltip Customization
export function CustomTooltip() {
const data = [
{ row: 'Product A', column: 'Q1', value: 150, status: 'Good' },
{ row: 'Product A', column: 'Q2', value: 200, status: 'Excellent' },
{ row: 'Product B', column: 'Q1', value: 100, status: 'Fair' }
];
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
dataSourceSettings={{ xDataMapping: 'column', yDataMapping: 'row', valueMapping: 'value' }}
xAxis={{
valueType: 'Category'
}}
yAxis={{
valueType: 'Category'
}}
tooltipRender={(args) => {
// Get the data item
const item = data.find(d =>
d.row === args.content.row &&
d.column === args.content.column
);
// Custom tooltip content
args.content = `
<div style="padding: 10px;">
<strong>${item.row}</strong> - ${item.column}<br/>
Value: ${item.value}<br/>
Status: <span style="color: ${item.status === 'Good' ? 'green' : 'orange'}">${item.status}</span>
</div>
`;
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Tooltip Styling
<HeatMapComponent
id='heatmap'
dataSource={data}
tooltipSettings={{
border: { width: 2, color: '#333' },
textStyle: {
size: '12px',
color: '#fff'
},
template: 'tooltipTemplate'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
// In JSX, define template:
<div id='tooltipTemplate' style={{ display: 'none' }}>
<div>
<span style={{ color: 'red' }}>Value: ${value}</span>
</div>
</div>Mouse Events
Cell Click Event
<HeatMapComponent
id='heatmap'
dataSource={data}
cellClick={(args) => {
console.log(`Clicked cell at [${args.row}, ${args.column}]`);
// Perform custom action
alert(`Value: ${args.value}`);
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Cell Mouse Hover
export function HoverTracking() {
const [hoveredCell, setHoveredCell] = useState(null);
return (
<div>
<HeatMapComponent
id='heatmap'
dataSource={data}
cellSelected={(args) => {
setHoveredCell({
row: args.row,
column: args.column,
value: args.value
});
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
{hoveredCell && (
<div>
<p>Hovering: {hoveredCell.value}</p>
</div>
)}
</div>
);
}Interactive Patterns
Pattern 1: Click to Filter Data
import { useState } from 'react';
export function FilterableHeatmap() {
const [selectedRow, setSelectedRow] = useState(null);
const allData = [
{ row: 'Product A', column: 'Q1', value: 150 },
{ row: 'Product A', column: 'Q2', value: 200 },
{ row: 'Product B', column: 'Q1', value: 100 },
{ row: 'Product B', column: 'Q2', value: 180 }
];
const handleCellClick = (args) => {
setSelectedRow(args.row);
};
const filteredData = selectedRow
? allData.filter(d => d.row === selectedRow)
: allData;
return (
<div>
<HeatMapComponent
id='heatmap'
dataSource={filteredData}
cellClick={handleCellClick}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
<div style={{ marginTop: '10px' }}>
{selectedRow && (
<button onClick={() => setSelectedRow(null)}>
Clear Filter ({selectedRow})
</button>
)}
</div>
</div>
);
}Pattern 2: Double-Click to Edit
import { useState } from 'react';
export function EditableHeatmap() {
const [data, setData] = useState([
{ row: 'A', column: 'X', value: 100 },
{ row: 'A', column: 'Y', value: 200 },
{ row: 'B', column: 'X', value: 150 }
]);
const [editMode, setEditMode] = useState(null);
const [newValue, setNewValue] = useState('');
const handleDoubleClick = (args) => {
setEditMode({ row: args.row, column: args.column });
setNewValue(args.value);
};
const handleSave = () => {
const updatedData = data.map(d => {
if (d.row === editMode.row && d.column === editMode.column) {
return { ...d, value: parseInt(newValue) };
}
return d;
});
setData(updatedData);
setEditMode(null);
};
return (
<div>
<HeatMapComponent
id='heatmap'
dataSource={data}
cellDoubleClick={handleDoubleClick}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
{editMode && (
<div style={{ marginTop: '20px', padding: '10px', border: '1px solid #ddd' }}>
<h4>Edit Value</h4>
<input
type="number"
value={newValue}
onChange={(e) => setNewValue(e.target.value)}
/>
<button onClick={handleSave}>Save</button>
<button onClick={() => setEditMode(null)}>Cancel</button>
</div>
)}
</div>
);
}Pattern 3: Drill-Down Navigation
import { useState } from 'react';
export function DrillDownHeatmap() {
const [level, setLevel] = useState('summary'); // 'summary' or 'detail'
const [selectedCell, setSelectedCell] = useState(null);
const summaryData = [
{ row: 'Region A', column: 'Q1', value: 500 },
{ row: 'Region B', column: 'Q1', value: 450 }
];
const detailData = {
'Region A-Q1': [
{ row: 'Product A', column: 'Jan', value: 150 },
{ row: 'Product B', column: 'Jan', value: 200 }
]
};
const handleCellClick = (args) => {
const key = `${args.row}-${args.column}`;
setSelectedCell(key);
setLevel('detail');
};
const currentData = level === 'summary'
? summaryData
: detailData[selectedCell];
return (
<div>
<h3>{level === 'summary' ? 'Summary View' : 'Detail View'}</h3>
<HeatMapComponent
id='heatmap'
dataSource={currentData}
cellClick={handleCellClick}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
{level === 'detail' && (
<button onClick={() => setLevel('summary')} style={{ marginTop: '10px' }}>
Back to Summary
</button>
)}
</div>
);
}Pattern 4: Export Selected Data
export function ExportableHeatmap() {
const [selectedCells, setSelectedCells] = useState([]);
const handleCellClick = (args) => {
setSelectedCells([...selectedCells, {
row: args.row,
column: args.column,
value: args.value
}]);
};
const exportToCSV = () => {
let csv = 'Row,Column,Value\n';
selectedCells.forEach(cell => {
csv += `${cell.row},${cell.column},${cell.value}\n`;
});
// Create download link
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'heatmap-data.csv';
a.click();
};
return (
<div>
<HeatMapComponent
id='heatmap'
dataSource={data}
cellClick={handleCellClick}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
<div style={{ marginTop: '15px' }}>
<p>Selected cells: {selectedCells.length}</p>
{selectedCells.length > 0 && (
<button onClick={exportToCSV}>Export Selected as CSV</button>
)}
</div>
</div>
);
}Legend, Appearance & Styling
Table of Contents
- Legend Basics
- Enable Legend
- Legend Properties
- Legend Placement
- Right Position (Default)
- Bottom Position
- Top Position
- Left Position
- Responsive Legend Positioning
- Legend Customization
- Title and Labels
- Legend Type: List
- Custom Legend Size
- Remove Legend
- Color Palettes
- Default Palettes
- Custom Gradient Palette
- Fixed Color Mapping (Non-Continuous)
- Colorblind-Friendly Palettes
- Dimensions & Sizing
- Fixed Dimensions with Scrolling
- Rendering Modes
- Automatic Mode Selection
- Force SVG Mode
- Force Canvas Mode
- CSS Styling
- Global Theme CSS
- Custom CSS Styling
- Cell-Level Styling
- Theme Integration
- Light Theme
- Dark Theme
- Complete Styling Example
Legend Basics
Enable Legend
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
<HeatMapComponent id='heatmap' dataSource={data}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>The legend displays a color scale showing the mapping between values and colors.
Legend Properties
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
position: 'Right', // Position: 'Right', 'Bottom', 'Top', 'Left'
visible: true, // Show/hide legend
width: '150px', // Legend width
height: 'auto', // Legend height
title: { text: 'Value Range' },
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Legend Placement
Right Position (Default)
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
position: 'Right',
width: '150px',
alignment: 'Center'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Use when: You have extra horizontal space and a tall heatmap.
Bottom Position
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
position: 'Bottom',
height: '80px',
alignment: 'Center'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Use when: You have extra vertical space or limited height.
Top Position
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
position: 'Top',
alignment: 'Far' // 'Near', 'Center', 'Far'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Use when: Legend should appear above the heatmap data.
Left Position
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
position: 'Left',
alignment: 'Center'
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Responsive Legend Positioning
import { useState, useEffect } from 'react';
export function ResponsiveHeatmap() {
const [legendPosition, setLegendPosition] = useState('Right');
useEffect(() => {
function handleResize() {
const width = window.innerWidth;
// Legend at bottom on mobile, right on desktop
setLegendPosition(width < 768 ? 'Bottom' : 'Right');
}
handleResize();
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
position: legendPosition
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Legend Customization
Title and Labels
<HeatMapComponent
id='heatmap'
dataSource={data}
legendRender={(args) => {
args.text = args.text + ' units';
}
}
legendSettings={{
position: 'Right',
title: {
text: 'Temperature (°C)',
textStyle: {
size: '14px',
fontWeight: 'bold',
color: '#333'
}
},
labelFormat: '{value}°', // Format legend labels
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Legend Type: List
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
mode: 'Categories'
}}
palette={[
{ value: 0, color: '#3498db' }, // Blue: Low
{ value: 50, color: '#f39c12' }, // Orange: Medium
{ value: 100, color: '#e74c3c' } // Red: High
]}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Custom Legend Size
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
position: 'Right',
width: '200px',
height: '300px',
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Remove Legend
<HeatMapComponent
id='heatmap'
dataSource={data}
legendSettings={{
visible: false // Hide legend completely
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Color Palettes
Default Palettes
// Blue-Green (good for data analysis)
palette={[
{ value: 0, color: '#3498db' },
{ value: 100, color: '#2ecc71' }
]}
// Red-Yellow-Green (traffic light style)
palette={[
{ value: 0, color: '#e74c3c' },
{ value: 50, color: '#f39c12' },
{ value: 100, color: '#2ecc71' }
]}
// Purple-White (heatmap style)
palette={[
{ value: 0, color: '#f7f7f7' },
{ value: 100, color: '#7b3ff2' }
]}Custom Gradient Palette
<HeatMapComponent
id='heatmap'
dataSource={data}
paletteSettings={{
palette: [{ value: 0, color: '#1a1a2e' }, // Very dark blue
{ value: 25, color: '#16213e' }, // Dark blue
{ value: 50, color: '#0f3460' }, // Medium blue
{ value: 75, color: '#ee2e24' }, // Red-orange
{ value: 100, color: '#ffff00' }]
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Fixed Color Mapping (Non-Continuous)
const data = [
{ row: 'App A', column: 'Mon', value: 1, status: 'healthy' },
{ row: 'App A', column: 'Tue', value: 2, status: 'warning' },
{ row: 'App B', column: 'Mon', value: 3, status: 'critical' }
];
<HeatMapComponent
id='heatmap'
dataSource={data}
dataSourceSettings={{ valueMapping: 'value' }}
paletteSettings={{
palette: [{ value: 1, color: '#2ecc71' }, // Green: healthy
{ value: 2, color: '#f39c12' }, // Orange: warning
{ value: 3, color: '#e74c3c' }]
}}
cellRender={(args) => {
const statusMap = {
'healthy': '✓',
'warning': '⚠',
'critical': '✕'
};
const status = data.find(d =>
d.row === args.row && d.column === args.column
)?.status;
args.displayText = statusMap[status] || '';
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Colorblind-Friendly Palettes
// Deuteranopia-friendly (red-green colorblind)
const colorblindPalette = [
{ value: 0, color: '#e8e8e8' }, // Light gray
{ value: 50, color: '#b3b3b3' }, // Medium gray
{ value: 100, color: '#212121' } // Dark gray
];
// Better: Viridis-style (works for most color blindness)
const viridis = [
{ value: 0, color: '#440154' },
{ value: 50, color: '#31688e' },
{ value: 100, color: '#35b779' }
];Dimensions & Sizing
Fixed Dimensions with Scrolling
<div style={{
width: '800px',
height: '600px',
overflow: 'auto',
border: '1px solid #ddd'
}}>
<HeatMapComponent
id='heatmap'
dataSource={largeData}
width='100%'
height='100%'
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>Rendering Modes
Automatic Mode Selection
<HeatMapComponent
id='heatmap'
dataSource={data}
renderingMode='Auto' // Switches to Canvas if >1000 cells
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>The component automatically chooses:
- SVG for small datasets (<1000 cells) - Better for styling
- Canvas for large datasets (>1000 cells) - Better performance
Force SVG Mode
<HeatMapComponent
id='heatmap'
dataSource={data}
renderingMode='SVG' // Always use SVG
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Use when: You need detailed styling and have small data.
Force Canvas Mode
<HeatMapComponent
id='heatmap'
dataSource={largeData}
renderingMode='Canvas' // Always use Canvas
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Use when: Performance is critical with large data.
CSS Styling
Global Theme CSS
// Material theme (Material Design colors)
import '@syncfusion/ej2-base/styles/material.css';
// Bootstrap 5 theme
import '@syncfusion/ej2-base/styles/bootstrap5.css';
// Fluent theme (Microsoft Fluent Design)
import '@syncfusion/ej2-base/styles/fabric.css';
// Tailwind theme
import '@syncfusion/ej2-base/styles/tailwind.css';Custom CSS Styling
import '@syncfusion/ej2-base/styles/material.css';
import './CustomHeatmap.css';
export function App() {
return (
<div className='custom-heatmap-container'>
<HeatMapComponent id='heatmap' dataSource={data}>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>
);
}CustomHeatmap.css:
.custom-heatmap-container .e-heatmap {
border: 2px solid #333;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
.custom-heatmap-container .e-heatmap-labels {
font-family: 'Arial', sans-serif;
font-weight: bold;
}
.custom-heatmap-container .e-heatmap-cell {
border-radius: 2px;
}Cell-Level Styling
<HeatMapComponent
id='heatmap'
dataSource={data}
cellRender={(args) => {
// Highlight cells above threshold
if (args.value > 80) {
args.cellElement.style.borderWidth = '2px';
args.cellElement.style.borderColor = '#000';
}
// Add patterns or icons
if (args.value < 20) {
args.displayText = '❄️'; // Freezing
} else if (args.value > 80) {
args.displayText = '🔥'; // Hot
}
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>Theme Integration
Light Theme
import '@syncfusion/ej2-base/styles/material.css';
export function App() {
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
// Light colors work well
paletteSettings={{
palette: [{ value: 0, color: '#e8f4f8' },
{ value: 100, color: '#0066cc' }]
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Dark Theme
import '@syncfusion/ej2-base/styles/material-dark.css';
export function App() {
return (
<HeatMapComponent
id='heatmap'
dataSource={data}
// Bright colors for dark backgrounds
paletteSettings={{
palette: [{ value: 0, color: '#1a1a2e' },
{ value: 100, color: '#00ff88' }]
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
);
}Complete Styling Example
import { HeatMapComponent, Inject, Legend, Tooltip } from '@syncfusion/ej2-react-heatmap';
import '@syncfusion/ej2-base/styles/bootstrap5.css';
import './HeatmapStyles.css';
export function StyledHeatmap() {
const data = [
{ row: 'Product A', column: 'Q1', value: 150 },
{ row: 'Product A', column: 'Q2', value: 200 },
{ row: 'Product B', column: 'Q1', value: 100 },
{ row: 'Product B', column: 'Q2', value: 180 }
];
return (
<div className='heatmap-wrapper'>
<div className='heatmap-header'>
<h2>Quarterly Performance</h2>
<p className='subtitle'>Sales data across products</p>
</div>
<HeatMapComponent
id='heatmap'
dataSource={data}
dataSourceSettings={{ xDataMapping: 'column', yDataMapping: 'row', valueMapping: 'value' }}
xAxis={{
valueType: 'Category'
}}
yAxis={{
valueType: 'Category'
}}
paletteSettings={{
palette: [{ value: 0, color: '#e3f2fd' },
{ value: 50, color: '#42a5f5' },
{ value: 100, color: '#1565c0' }]
}}
legendSettings={{
position: 'Right',
title: { text: 'Sales Volume' }
}}
>
<Inject services={[Legend, Tooltip]} />
</HeatMapComponent>
</div>
);
}HeatmapStyles.css:
.heatmap-wrapper {
padding: 20px;
background: #f5f5f5;
border-radius: 8px;
}
.heatmap-header {
margin-bottom: 20px;
}
.heatmap-header h2 {
color: #333;
margin: 0 0 5px 0;
}
.subtitle {
color: #666;
font-size: 14px;
margin: 0;
}