GUI controls for manipulating Highcharts charts, Grid, and Dashboards options on the fly. The control library can be used both as chart-bound controls and as reusable standalone UI controls without attaching to a Highcharts target.
Load the module file from a CDN or your own server
<script type="module" src="https://cdn.jsdelivr.net/npm/@highcharts/controls@0.9.0"></script>Or
import Controls from 'https://cdn.jsdelivr.net/npm/@highcharts/controls@0.9.0';<!DOCTYPE html>
<html>
<head>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@highcharts/controls@0.9.0"></script>
</head>
<body>
<div id="container"></div>
<script>
Highcharts.chart('container', {
title: { text: 'My Chart' },
series: [{
data: [1, 2, 3, 4, 5]
}]
});
</script>
<highcharts-controls target="#container">
<highcharts-group header="Legend Settings">
<highcharts-control
type="boolean"
path="legend.enabled"
value="true">
</highcharts-control>
<highcharts-control
type="select"
path="legend.align"
options="left,center,right"
value="center">
</highcharts-control>
<highcharts-control
type="number"
path="legend.x">
</highcharts-control>
<highcharts-control
type="color"
path="legend.backgroundColor"
nullable
value="#FFEEAA">
</highcharts-control>
</highcharts-group>
</highcharts-controls>
</body>
</html>Standalone controls do not use a path and work like native HTML inputs. You can bind to the change event and update the value programmatically with the value property.
<!DOCTYPE html>
<html>
<head>
<script type="module" src="https://cdn.jsdelivr.net/npm/@highcharts/controls@0.9.0"></script>
</head>
<body>
<highcharts-control
id="theme-color"
type="color"
label="Primary Color"
value="#3498db">
</highcharts-control>
<script type="module">
const themeColor = document.getElementById('theme-color');
themeColor.addEventListener('change', (event) => {
console.log('Color changed:', event.detail.value);
document.body.style.backgroundColor = event.detail.value;
});
// Update the control value programmatically
themeColor.value = '#e74c3c';
</script>
</body>
</html><!DOCTYPE html>
<html>
<head>
<script src="https://code.highcharts.com/highcharts.js"></script>
<script type="module" src="https://cdn.jsdelivr.net/npm/@highcharts/controls@0.9.0"></script>
</head>
<body>
<div id="container"></div>
<div id="controls-container"></div>
<script type="module">
// Create a chart
Highcharts.chart('container', {
title: { text: 'My Chart' },
series: [{
data: [1, 2, 3, 4, 5]
}]
});
// Add controls
HighchartsControls.controls('controls-container', {
controls: [
{
group: 'Legend Settings',
controls: [
{
// Type is optional - automatically deduced from value
path: 'legend.enabled',
value: true
},
{
path: 'legend.align',
options: ['left', 'center', 'right'],
value: 'center'
},
{
path: 'legend.x',
min: -100,
max: 100,
step: 10,
value: 0
},
{
path: 'legend.backgroundColor',
nullable: true,
value: '#FFEEAA'
}
]
}
]
});
</script>
</body>
</html>By default, the Highcharts Controls renders in an inline-block element, shrinking
to fit its content. This works well for compact controls. For wider layouts that
should take 100% of the parent's width, set the display option to 'block'.
Web Components:
<highcharts-controls display="block">
<!-- controls here -->
</highcharts-controls>JavaScript API:
HighchartsControls.controls('controls-container', {
display: 'block', // or 'inline-block' (default)
controls: [
// ...
]
});Creates a controls instance.
Parameters:
container(string | HTMLElement) - The container element or element ID where controls will be renderedoptions(ControlsOptionsObject) - Configuration options
Returns: Controls instance
interface ControlsOptionsObject {
target?: ControlTarget; // Target chart/grid (defaults to first chart)
injectCSS?: boolean; // Auto-inject CSS (defaults to true)
display?: 'block' | 'inline-block'; // Display mode (defaults to 'inline-block')
showPreview?: boolean; // Show the live options preview (defaults to true)
controls: Array<ControlParams | GroupParams>; // Array of control or group configurations
}Set showPreview: false to hide the preview toggle and preview panel when you want a cleaner standalone control layout without the live options inspector.
HighchartsControls.controls('controls-container', {
showPreview: false,
controls: [
{ path: 'legend.enabled', value: true },
{ path: 'legend.align', options: ['left', 'center', 'right'], value: 'center' }
]
});Controls can be organized into collapsible groups with headers:
interface GroupParams {
group: string; // Group header text
description?: string; // Optional description text
controls: ControlParams[]; // Controls within the group
collapsed?: boolean; // Initial collapsed state (default: false)
collapsible?: boolean; // Allow expand/collapse (default: false)
className?: string; // Custom CSS class
}Example:
HighchartsControls.controls('controls-container', {
controls: [
{
group: 'Legend Settings',
description: 'Control the appearance and behavior of the chart legend.',
collapsible: true, // Enable expand/collapse
collapsed: false, // Start expanded
controls: [
{ path: 'legend.enabled', value: true },
{ path: 'legend.align', options: ['left', 'center', 'right'] }
]
},
{
group: 'Chart Settings',
collapsible: true, // Enable expand/collapse
collapsed: true, // Start collapsed
controls: [
{ path: 'chart.backgroundColor', value: '#FFFFFF' }
]
},
// Ungrouped controls can be mixed with groups
{ path: 'title.text', value: 'My Chart' }
]
});Note: The type parameter is optional. If omitted, the library will automatically deduce the control type based on the value and other parameters:
- Boolean values →
booleancontrol - Numeric values or strings with units (px, em, rem, %) →
numbercontrol - Presence of
optionsarray →selectcontrol - Strings containing "color" in the path or valid color values →
colorcontrol - Other string values →
textcontrol (fallback)
Toggle chart options on/off with a styled checkbox.
{
type: 'boolean',
path: 'legend.enabled', // Dot-separated path to option
value: true, // Initial value (optional)
nullable: true // Enable tri-state toggle (optional)
}Nullable behavior: When nullable: true, the control becomes a tri-state toggle with a wider slider that cycles through false (left) → null (middle) → true (right). The middle position shows a diagonal striped pattern and applies the hcc-control-nullish class.
Select from predefined options with button group.
{
type: 'select',
path: 'legend.align',
options: ['left', 'center', 'right'], // Available options
value: 'center', // Initial selection (optional)
nullable: true // Add null option (optional)
}Nullable behavior: When nullable: true, adds a null option:
- Button group mode: Adds a button with ⊘ symbol as the rightmost button
- Dropdown mode: Adds "—" as the first option
Clicking the null option sets the value to null and applies the hcc-control-nullish class.
Adjust numeric values with a range slider. Supports length units like px, em, rem, and %.
{
type: 'number',
path: 'legend.x',
min: -100, // Minimum value (optional)
max: 100, // Maximum value (optional)
step: 10, // Step increment (optional, defaults to 1)
value: 0, // Initial value (optional, can be number or string with unit)
nullable: true // Add nullable button (optional)
}Nullable behavior: When nullable: true, adds a ⊘ button to the right of the control. Clicking it clears the value display and sets the value to null. The range slider remains interactive and becomes visually dimmed (reduced opacity and saturation). User can adjust the slider at any time to restore a value.
Unit Support:
The number control seamlessly handles length units commonly used in Highcharts:
// With em units (step defaults to 0.1 for em/rem)
{
type: 'number',
path: 'title.style.fontSize',
min: 0.5,
max: 3,
value: '1.5em' // Unit extracted from string value
}
// With percentage units
{
type: 'number',
path: 'chart.height',
min: 50,
max: 100,
value: '80%'
}Default min/max (when not specified):
- Properties ending in
lineWidthorborderWidth: min: 0, max: 5 - Properties ending in
x,y,offsetX,offsetY, oroffset: min: -100, max: 100 - Other properties: min: 0, max: 100
Unit behavior:
- Units are extracted from the
valuestring (e.g.,'1.5em','60px','80%') - The control displays the numeric value with the unit (e.g., "1.5em")
- Chart options receive the value with the unit as a string
- For
emandremunits,stepdefaults to0.1if not specified
Choose colors with a color picker and opacity control.
{
type: 'color',
path: 'chart.backgroundColor',
value: '#FFFFFF', // Initial color (optional)
nullable: true // Add nullable button (optional)
}Nullable behavior: When nullable: true, adds a ⊘ button to the right of the control. Clicking it shows "—" in the color value display and sets the value to null. The color picker and opacity slider remain interactive, allowing immediate color selection to restore a value.
Edit text values with a text input field.
{
type: 'text',
path: 'title.text',
value: 'My Chart Title', // Initial text (optional)
nullable: true // Add nullable button (optional)
}Nullable behavior: When nullable: true, adds a ⊘ button to the right of the control. Clicking it clears the input, shows a "null" placeholder, and sets the value to null. The input remains active and typing immediately removes the placeholder and restores a value.
Add a visual separator (horizontal rule) between controls to group related functionality.
JavaScript API:
HighchartsControls.controls('controls-container', {
controls: [
{ path: 'legend.enabled', value: true },
{ path: 'legend.align', options: ['left', 'center', 'right'] },
{ type: 'separator' }, // Add separator
{ path: 'chart.backgroundColor', value: '#FFFFFF' }
]
});Web Components:
<highcharts-controls>
<highcharts-control path="legend.enabled" value="true"></highcharts-control>
<highcharts-control path="legend.align" options="left,center,right"></highcharts-control>
<highcharts-separator></highcharts-separator>
<highcharts-control path="chart.backgroundColor" value="#FFFFFF"></highcharts-control>
</highcharts-controls>Within groups:
{
group: 'Settings',
controls: [
{ path: 'legend.enabled', value: true },
{ type: 'separator' },
{ path: 'chart.backgroundColor', value: '#FFFFFF' }
]
}When a control's value is null or undefined, each control type displays a distinct visual state to clearly indicate that no value has been set:
- Boolean controls: Display as unchecked with a diagonal striped pattern on the toggle slider
- Color controls: Show an em-dash (—) placeholder instead of a color value, with a striped pattern in the color picker swatch
- Number controls: Display the range slider but hide the numeric label
- Select controls: No button is marked as active (or no option selected in dropdown)
- Text controls: Show an empty input field
Note: Select controls automatically render as a dropdown when there are more than 3 options or the total string length of all options exceeds 24 characters. Otherwise, they display as a button group.
This typically happens if the value is not set, and the Controls are unable to
read the value from the target chart or grid. In some cases, chart or grid
defaults are null or undefined, indicating the behavior depends on other states.
<highcharts-controls>
<highcharts-control path="chart.inverted" type="boolean"></highcharts-control>
<highcharts-control path="legend.backgroundColor" type="color"></highcharts-control>
</highcharts-control>When a user interacts with a control in nullish state (types text, clicks toggle, changes color, moves slider, or selects option), the visual nullish indicators are automatically removed and the control behaves normally.
CSS Classes:
- All controls in nullish state receive the
hcc-control-nullishclass - Each control type also receives a type-specific class (
hcc-control-boolean,hcc-control-color,hcc-control-number,hcc-control-select,hcc-control-text) for targeted styling
Container element for controls.
Attributes:
target(optional) - CSS selector for target chart container (e.g.,"#container")inject-css(optional) - Set to"false"to disable automatic CSS injectiondisplay(optional) - Display mode:"block"or"inline-block"(default:"inline-block")
Example:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@highcharts/controls@0.9.0/css/controls.css" />
<highcharts-controls target="#my-chart" inject-css="false">
<!-- controls here -->
</highcharts-controls>Group controls under a collapsible header. Must be a child of <highcharts-controls>.
Attributes:
header(required) - Header text for the groupcollapsed(optional) - Set to"true"to start collapsedcollapsible(optional) - Set to"true"to enable expand/collapse (default: false)class(optional) - Custom CSS class
Child Elements:
<highcharts-group-description>(optional) - Description text displayed below the header. Supports HTML markup.<highcharts-control>- Individual controls within the group<highcharts-separator>- Visual separator between controls
Note: When using <highcharts-group-description> and injectCSS is set to true (default), it's recommended to add this to your page CSS to avoid a flash of unstyled content (FOUC):
highcharts-group-description,
highcharts-separator {
display: none;
}Example:
<highcharts-controls target="#container">
<highcharts-group header="Legend Settings" collapsible="true">
<highcharts-group-description>
Control the appearance and behavior of the chart legend.
</highcharts-group-description>
<highcharts-control path="legend.enabled" value="true"></highcharts-control>
<highcharts-control path="legend.align" options="left,center,right"></highcharts-control>
</highcharts-group>
<highcharts-group header="Chart Settings" collapsible="true" collapsed="true">
<highcharts-control path="chart.backgroundColor" value="#FFFFFF"></highcharts-control>
</highcharts-group>
<!-- Ungrouped controls -->
<highcharts-control path="title.text" value="My Chart"></highcharts-control>
</highcharts-controls>Insert a horizontal separator line between controls. Must be a child of <highcharts-controls> or <highcharts-group>.
Attributes: None
Example:
<highcharts-controls target="#container">
<highcharts-control path="legend.enabled" value="true"></highcharts-control>
<highcharts-control path="legend.align" options="left,center,right"></highcharts-control>
<highcharts-separator></highcharts-separator>
<highcharts-control path="chart.backgroundColor" value="#FFFFFF"></highcharts-control>
<highcharts-control path="title.text" value="My Chart"></highcharts-control>
</highcharts-controls>Individual control element.
Attributes:
type(required) - Control type:"boolean","select","number","color", or"text"path(required) - Dot-separated path to chart option (e.g.,"legend.enabled")value(optional) - Initial valueoptions(required for select) - Comma-separated list of optionsmin(optional for number) - Minimum value for range slidermax(optional for number) - Maximum value for range sliderstep(optional for number) - Step increment for range slidernullable(optional) - Add nullable button/option to allow setting null values (attribute presence enables it)
Examples:
<!-- Boolean -->
<highcharts-control
type="boolean"
path="legend.enabled"
value="true">
</highcharts-control>
<!-- Select -->
<highcharts-control
type="select"
path="legend.align"
options="left,center,right"
value="center">
</highcharts-control>
<!-- Number -->
<highcharts-control
type="number"
path="legend.x"
min="-100"
max="100"
step="10">
</highcharts-control>
<!-- Number with units -->
<highcharts-control
type="number"
path="title.style.fontSize"
min="0.5"
max="3"
value="1.5em">
</highcharts-control>
<highcharts-control
type="number"
path="chart.marginTop"
min="0"
max="200"
value="60px">
</highcharts-control>
<!-- Color -->
<highcharts-control
type="color"
path="chart.backgroundColor"
value="#FFFFFF">
</highcharts-control>
<!-- Text -->
<highcharts-control
type="text"
path="title.text"
value="My Chart Title">
</highcharts-control>
<!-- With nullable option -->
<highcharts-control
type="boolean"
path="legend.enabled"
nullable>
</highcharts-control>
<highcharts-control
type="text"
path="subtitle.text"
nullable>
</highcharts-control>- Live Preview - See chart options update in real-time
- Options Inspector - View current chart configuration as JSON
- Standalone Controls - Use individual controls independently without a target chart or grid
- Type Safety - Full TypeScript support with type definitions
- Auto-injection - Optionally inject CSS automatically
- Flexible Targeting - Target specific charts or use defaults
- Modern UI - Clean, styled controls with smooth animations
The Highcharts Controls support using individual controls standalone, without requiring a Highcharts/Grid target. This makes controls reusable as general-purpose UI components.
✅ Standalone Controls - Use controls independently without a target chart ✅ Event-Driven - Standard DOM EventTarget-based event handling ✅ Modular - Import only the controls you need ✅ Type-Safe - Full TypeScript support ✅ Backward Compatible - Existing API continues to work
For standalone controls, omit path and treat the control like a native HTML input: the value is managed directly by the control instance.
import { ColorControl } from '@highcharts/controls';
// Create a standalone color picker
const colorPicker = new ColorControl({
type: 'color',
label: 'Primary Color',
value: '#3498db'
});
// Render it anywhere in your UI
colorPicker.render(document.getElementById('my-container'));
// Listen for changes
colorPicker.addEventListener('change', (e) => {
console.log('Color changed:', e.detail.value);
document.body.style.backgroundColor = e.detail.value;
});
// Programmatically update the value
colorPicker.value = '#e74c3c';import { NumberControl } from '@highcharts/controls';
const volumeSlider = new NumberControl({
type: 'number',
label: 'Volume',
value: 50,
min: 0,
max: 100,
step: 1
});
volumeSlider.render(document.getElementById('volume-control'));
volumeSlider.addEventListener('change', (e) => {
audioElement.volume = e.detail.value / 100;
});import { BooleanControl } from '@highcharts/controls';
const darkModeToggle = new BooleanControl({
type: 'boolean',
label: 'Dark Mode',
value: false
});
darkModeToggle.render(document.getElementById('theme-toggle'));
darkModeToggle.addEventListener('change', (e) => {
document.body.classList.toggle('dark-mode', e.detail.value);
});You can also pre-create controls with custom behavior, then pass them to the Controls collection:
import Controls, { ColorControl } from '@highcharts/controls';
// Create a control with custom logic
const customColor = new ColorControl({
label: 'Chart Background',
value: '#fff'
});
customColor.addEventListener('change', (e) => {
// Custom validation or transformation
if (isValidColor(e.detail.value)) {
console.log('Valid color selected');
}
});
// Use it in the collection
const controls = new Controls(container, {
target: chart,
controls: [
customColor, // Pass the instance directly
{ type: 'boolean', path: 'legend.enabled' } // Or use config
]
});Control- Base class for all controlsColorControl- Color picker with opacity sliderBooleanControl- Toggle switch (supports tri-state nullable)NumberControl- Range slider with unit supportSelectControl- Dropdown or button group (function-based, to be refactored)TextControl- Text input (function-based, to be refactored)
All controls emit a 'change' event with the following detail:
{
value: any, // New value
oldValue: any, // Previous value
path: string, // Control path
animation?: boolean // Animation flag (NumberControl only)
}All control instances have these methods:
render(container: HTMLElement)- Render the control into a containerdestroy()- Clean up event listeners and remove from DOMgetElement()- Get the control's root DOM element
And these properties:
value- Get or set the control's value programmaticallyparams- Access the control's configuration parameters
- Decoupled - Controls no longer require Highcharts/Datagrid
- Reusable - Use anywhere in your application
- Testable - Each control can be unit tested in isolation
- Flexible - Compose controls however you want
- Progressive Enhancement - Add chart binding only when needed
ISC
Torstein Hønsi