DevExtreme React - SVG-Based Components Customization

This article describes ways to customize SVG-based UI components. For a list of SVG-based UI components, refer to Styling Methods. A similar article on HTML-based UI components is also available.

Palettes

A palette is a set of colors that mix well with each other. Palettes are used to colorize the following UI component elements:

DevExtreme supports predefined and custom palettes. The default palette is Material. This and other predefined palettes are demonstrated in the following demo:

View Demo

Apply a Palette

Every UI component that supports palettes has a palette property. It accepts the name of a predefined or registered custom palette or an array of colors. In most UI components, this property should be set on the first level of the configuration object:

jQuery
JavaScript
$(function() {
    $("#pieChartContainer").dxPieChart({
        // ...
        palette: "Harmony Light"
        // ===== or custom colors =====
        // palette: ['#60a69f', '#78b6d9', '#6682bb', '#a37182', '#eeba69']
    });
});
Angular
HTML
TypeScript
<dx-pie-chart ... 
    palette="Harmony Light">
    <!-- or custom colors -->
    <!-- [palette]="['#60a69f', '#78b6d9', '#6682bb', '#a37182', '#eeba69']"> -->
</dx-pie-chart>
import { DxPieChartModule } from "devextreme-angular";
// ...
export class AppComponent {
    // ...
}
@NgModule({
    imports: [
        // ...
        DxPieChartModule
    ],
    // ...
})
Vue
<template>
    <DxPieChart ...
        palette="Harmony Light">
        <!-- or custom colors -->
        <!-- :palette="['#60a69f', '#78b6d9', '#6682bb', '#a37182', '#eeba69']"> -->
    </DxPieChart>
</template>

<script>
import { DxPieChart } from 'devextreme-vue/pie-chart';

export default {
    components: {
        DxPieChart
    }
}
</script>
React
import React from 'react';
import { PieChart } from 'devextreme-react/pie-chart';

const customPalette = ['#60a69f', '#78b6d9', '#6682bb', '#a37182', '#eeba69'];

class App extends React.Component {
    render() {
        return (
            <PieChart ...
                palette="Harmony Light">
                {/* ===== or custom colors ===== */}
                {/* palette={customPalette}> */}
            </PieChart>
        );
    }
}

export default App;

View Demo

In the CircularGauge and LinearGauge, the palette can be specified in the rangeContainer and subvalueIndicator objects.

jQuery
JavaScript
$(function() {
    $("#circularGaugeContainer").dxCircularGauge({
        // ...
        subvalues: [25, 40, 68],
        subvalueIndicator: {
            palette: "Soft Pastel"
        },
        rangeContainer: {
            ranges: [
                { startValue: 0, endValue: 30 },
                { startValue: 30, endValue: 70 },
                { startValue: 70, endValue: 100 },
            ],
            palette: "Violet"
        }
    });
});
Angular
app.component.html
app.module.ts
<dx-circular-gauge ...
    [subvalues]="[25, 40, 68]">
    <dxo-subvalue-indicator
        palette="Soft Pastel">
    </dxo-subvalue-indicator>
    <dxo-range-container palette="Harmony Light">
        <dxi-range [startValue]="0" [endValue]="30"></dxi-range>
        <dxi-range [startValue]="30" [endValue]="70"></dxi-range>
        <dxi-range [startValue]="70" [endValue]="100"></dxi-range>
    </dxo-range-container>
</dx-circular-gauge>
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { DxCircularGaugeModule } from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxCircularGaugeModule
    ],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
Vue
App.vue
<template>
    <DxCircularGauge ...
        :subvalues="[25, 40, 68]">
        <DxSubvalueIndicator
            palette="Soft Pastel" />
        <DxRangeContainer palette="Harmony Light">
            <DxRange :start-value="0" :end-value="30" />
            <DxRange :start-value="30" :end-value="70" />
            <DxRange :start-value="70" :end-value="100" />
        </DxRangeContainer>
    </DxCircularGauge>
</template>
<script>
import {
    DxCircularGauge,
    DxRangeContainer,
    DxRange,
    DxSubvalueIndicator
} from 'devextreme-vue/circular-gauge';

export default {
    components: {
        DxCircularGauge,
        DxRangeContainer,
        DxRange,
        DxSubvalueIndicator
    }
}
</script>
React
App.js
import React from 'react';
import { CircularGauge, RangeContainer, Range, SubvalueIndicator } from 'devextreme-react/circular-gauge';

const subvalues = [25, 40, 68];

class App extends React.Component {
    render() {
        return (
            <CircularGauge
                subvalues={subvalues}>
                <SubvalueIndicator palette="Soft Pastel" />
                <RangeContainer palette="Violet">
                    <Range startValue={0} endValue={30} />
                    <Range startValue={30} endValue={70} />
                    <Range startValue={70} endValue={100} />
                </RangeContainer>
            </CircularGauge>
        );
    }
}

export default App;

View Demo

In the TreeMap, the palette is part of the colorizer. In the VectorMap, it should be set for a specific layer. In the RangeSelector, the palette is specified in the chart object.

jQuery
JavaScript
$(function() {
    $("#treeMapContainer").dxTreeMap({
        // ...
        colorizer: {
            palette: "Violet"
        }
    });

    $("#vectorMapContainer").dxVectorMap({
        // ...
        layers: [{
            dataSource: DevExpress.viz.map.sources.world,
            palette: "Violet",
            paletteSize: 7,
            customize: function(elements) {
                elements.forEach(function(element, index) {
                    element.applySettings({
                        paletteIndex: index % 7
                    });
                });
            }
        }]
    });

    $("#rangeSelectorContainer").dxRangeSelector({
        dataSource: [
            { arg: "A", val1: 1, val2: 3 },
            { arg: "B", val1: 5, val2: 5 },
            { arg: "C", val1: 10, val2: 7 }
        ],
        chart: {
            palette: "Soft Pastel",
            commonSeriesSettings: {
                type: "bar",
                argumentField: "arg"
            },
            series: [
                { valueField: "val1" },
                { valueField: "val2" }
            ]
        }
    });
});
Angular
app.component.html
app.component.ts
app.module.ts
<dx-tree-map ... >
    <dxo-colorizer palette="Harmony Light"></dxo-colorizer>
</dx-tree-map>

<dx-vector-map ... >
    <dxi-layer
        [dataSource]="worldMap"
        palette="Violet" 
        [paletteSize]="7"
        [customize]="colorizeMap">
    </dxi-layer>
</dx-vector-map>

<dx-range-selector
    [dataSource]="[
        { arg: 'A', val1: 1, val2: 3 },
        { arg: 'B', val1: 5, val2: 5 },
        { arg: 'C', val1: 10, val2: 7 }
    ]">
    <dxo-chart palette="Soft Pastel">
        <dxo-common-series-settings type="bar" argumentField="arg"></dxo-common-series-settings>
        <dxi-series value-field="val1"></dxi-series>
        <dxi-series value-field="val2"></dxi-series>
    </dxo-chart>
</dx-range-selector>
import { Component } from '@angular/core';
import * as mapsData from 'devextreme-dist/js/vectormap-data/world.js';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    constructor(service: Service) {
        this.colorizeMap = this.colorizeMap.bind(this);
    }

    worldMap: any = mapsData.world;

    colorizeMap(elements) {
        elements.forEach((element, index) => {
             element.applySettings({
                paletteIndex: index % 7
            });
        });
    }
}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { DxTreeMapModule, DxVectorMapModule, DxRangeSelector } from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxTreeMapModule,
        DxVectorMapModule,
        DxRangeSelector
    ],
    providers: [ ],
    bootstrap: [AppComponent]
})
export class AppModule { }
Vue
App.vue
<template>
    <div>
        <DxTreeMap ... >
            <DxColorizer palette="Harmony Light" />
        </DxTreeMap>

        <DxVectorMap ... >
            <DxLayer
                :data-source="worldMap"
                palette="Violet" 
                :palette-size="7"
                :customize="colorizeMap" />
        </DxVectorMap>

        <DxRangeSelector
            :data-source="[
                { arg: 'A', val1: 1, val2: 3 },
                { arg: 'B', val1: 5, val2: 5 },
                { arg: 'C', val1: 10, val2: 7 }
            ]">
            <DxChart palette="Soft Pastel">
                <DxCommonSeriesSettings type="bar" argument-field="arg" />
                <DxSeries value-field="val1" />
                <DxSeries value-field="val2" />
            <DxChart>
        </DxRangeSelector>
    </div>
</template>
<script>
import { DxTreeMap, DxColorizer } from 'devextreme-vue/tree-map';
import { DxVectorMap, DxLayer } from 'devextreme-vue/vector-map';
import * as mapsData from 'devextreme-dist/js/vectormap-data/world.js';
import {
    DxRangeSelector,
    DxChart,
    DxCommonSeriesSettings,
    DxSeries
} from 'devextreme-vue/range-selector';

export default {
    components: {
        DxTreeMap,
        DxColorizer,
        DxVectorMap,
        DxLayer,
        DxRangeSelector,
        DxChart,
        DxCommonSeriesSettings,
        DxSeries
    },
    data() {
        return {
            worldMap: mapsData.world
        }
    },
    methods: {
        colorizeMap(elements) {
            elements.forEach((element, index) => {
                element.applySettings({
                    paletteIndex: index % 7
                });
            });
        }
    }
}
</script>
React
App.js
import React from 'react';
import { TreeMap, Colorizer } from 'devextreme-react/tree-map';
import { VectorMap, Layer } from 'devextreme-react/vector-map';
import * as mapsData from 'devextreme-dist/js/vectormap-data/world.js';
import {
    RangeSelector,
    Chart,
    Series,
    CommonSeriesSettings
} from 'devextreme-react/range-selector';

const worldMap = mapsData.world;
const rangeSelectorData = [
    { arg: 'A', val1: 1, val2: 3 },
    { arg: 'B', val1: 5, val2: 5 },
    { arg: 'C', val1: 10, val2: 7 }
];

class App extends React.Component {
    render() {
        return (
            <div>
                <TreeMap ... >
                    <Colorizer palette="Violet" />
                </TreeMap>

                <VectorMap>
                    <Layer
                        dataSource={worldMap}
                        paletteSize={7}
                        customize={this.colorizeMap}
                        palette="Violet" />
                </VectorMap>

                <RangeSelector
                    dataSource={rangeSelectorData}>
                    <Chart palette="Soft Pastel">
                        <CommonSeriesSettings type="bar" argumentField="arg" />
                        <Series valueField="val1" />
                        <Series valueField="val2" />
                    </Chart>
                </RangeSelector>
            </div>
        );
    }

    colorizeMap(elements) {
        elements.forEach((element, index) => {
            element.applySettings({
                paletteIndex: index % 7
            });
        });
    }
}

export default App;

TreeMap Demo VectorMap Demo

Override a Palette Color

Set a UI component element's color property to override a palette color for this element:

jQuery
JavaScript
$(function() {
    $("#chartContainer").dxChart({
        // ...
        series: [{
            color: "red",
            // ...
        }, { /* ... */ }, { /* ... */ }]
    });

    $("#circularGaugeContainer").dxCircularGauge({
        // ...
        rangeContainer: {
            ranges: [{
                color: "red"
                // ...
            }, { /* ... */ }, { /* ... */ }]
        }
    });

    $("#vectorMapContainer").dxVectorMap({
        // ...
        layers: [{
            // ...
            customize: function(elements) {
                $.each(elements, function(_, element) {
                    element.applySettings({
                        color: "red"
                    });
                });
            }
        }, { /* ... */ }, { /* ... */ }]
    });
});
Angular
HTML
TypeScript
<dx-chart ... >
    <dxi-series color="red" ... ></dxi-series>
</dx-chart>

<dx-circular-gauge ... >
    <dxo-range-container>
        <!-- ... -->
        <dxi-range color="red" ... ></dxi-range>
    </dxo-range-container>
</dx-circular-gauge>

<dx-vector-map ... >
    <dxi-layer ...
        [customize]="colorizeMap">
    </dxi-layer>
</dx-vector-map>
import {
    DxChartModule,
    DxCircularGaugeModule,
    DxVectorMapModule
} from "devextreme-angular";
import * as mapsData from "devextreme-dist/js/vectormap-data/world.js";
// ...
export class AppComponent {
    worldMap: any = mapsData.world;
    constructor() {
        this.colorizeMap = this.colorizeMap.bind(this);
    }
    colorizeMap(elements) {
        elements.forEach((element) => {
             element.applySettings({
                color: "red"
            });
        });
    }
}
@NgModule({
    imports: [
        // ...
        DxChartModule
    ],
    // ...
})
Vue
<template>
    <div>
        <DxChart ... >
            <DxSeries color="red" ... />
        </DxChart>

        <DxCircularGauge ... >
            <DxRangeContainer ... >
                <DxRange color="red" ... />
            </DxRangeContainer>
        </DxCircularGauge>

        <DxVectorMap ... >
            <DxLayer ...
                :customize="colorizeMap" />
        </DxVectorMap>
    </div>
</template>
<script>
import { DxChart, DxSeries } from 'devextreme-vue/tree-map';
import { DxCircularGauge, DxRangeContainer, DxRange } from 'devextreme-vue/circular-gauge';
import { DxVectorMap, DxLayer } from 'devextreme-vue/vector-map';
import * as mapsData from 'devextreme-dist/js/vectormap-data/world.js';

export default {
    components: {
        DxChart,
        DxSeries,
        DxCircularGauge,
        DxRangeContainer,
        DxRange,
        DxVectorMap,
        DxLayer
    },
    data() {
        return {
            worldMap: mapsData.world
        }
    },
    methods: {
        colorizeMap(elements) {
            elements.forEach((element) => {
                element.applySettings({
                    color: 'red'
                });
            });
        }
    }
}
</script>
React
import React from 'react';
import { Chart, Series } from 'devextreme-react/chart';
import { CircularGauge, RangeContainer, Range } from 'devextreme-react/circular-gauge';
import { VectorMap, Layer } from 'devextreme-react/vector-map';
import * as mapsData from 'devextreme-dist/js/vectormap-data/world.js';

const worldMap = mapsData.world;

class App extends React.Component {
    render() {
        return (
            <div>
                <Chart ... >
                    <Series color="red" ... />
                </Chart>

                <CircularGauge ... >
                    <RangeContainer ... >
                        <Range color="red" ... />
                    </RangeContainer>
                </CircularGauge>

                <VectorMap>
                    <Layer ...
                        customize={this.colorizeMap} />
                </VectorMap>
            <div>
        );
    }

    colorizeMap(elements) {
        elements.forEach((element) => {
            element.applySettings({
                color: 'red'
            });
        });
    }
}

export default App;

Implement a Custom Palette

The easiest way to implement a custom palette is to assign an array of colors to the palette property (see Apply a Palette). However, this approach is only useful for a single UI component or several UI components of the same type.

In other cases, we recommend implementing a custom palette as an object of the following structure:

JavaScript
var myPalette = {
    // Applies in the BarGauge, Chart, Funnel, PieChart, PolarChart, Sankey, and TreeMap with a discrete colorizer
    simpleSet: ['#60a69f', '#78b6d9', '#6682bb', '#a37182', '#eeba69'], 
    // Applies in the CircularGauge and LinearGauge
    indicatingSet: ['#90ba58', '#eeba69', '#a37182'], 
    // Applies in the VectorMap and TreeMap with a gradient or range colorizer 
    gradientSet: ['#78b6d9', '#eeba69'] 
};

The custom palette should be registered using the registerPalette(paletteName, palette) method:

jQuery
index.js
DevExpress.viz.registerPalette("myCustomPalette", myPalette);
// ===== or when using modules =====
import { registerPalette } from "devextreme/viz/palette";

registerPalette("myCustomPalette", myPalette);
Angular
app.component.ts
import { registerPalette } from "devextreme/viz/palette";

registerPalette("myCustomPalette", myPalette);
Vue
App.vue
import { registerPalette } from "devextreme/viz/palette";

registerPalette("myCustomPalette", myPalette);
React
App.js
import { registerPalette } from "devextreme/viz/palette";

registerPalette("myCustomPalette", myPalette);

To apply it, assign the name used in the registration to the UI components' palette properties as shown in the Apply a Palette article.

Get a Registered Palette

Call the DevExpress.viz.getPalette(paletteName) method to get a registered predefined or custom palette. The method's description provides information about the structure of the returned object.

jQuery
index.js
const palette = DevExpress.viz.getPalette("Material");
// ===== or when using modules =====
import { getPalette } from "devextreme/viz/palette";

let palette = getPalette("Material");
Angular
app.component.ts
import { getPalette } from "devextreme/viz/palette";

let palette = getPalette("Material");
Vue
App.vue
import { getPalette } from "devextreme/viz/palette";

let palette = getPalette("Material");
React
App.js
import { getPalette } from "devextreme/viz/palette";

let palette = getPalette("Material");

Themes

Unlike CSS themes, which are collections of CSS classes, SVG themes are UI component configurations. However, all predefined CSS themes have SVG counterparts. This allows HTML- and SVG-based UI components to have a uniform appearance when they are displayed on the same page.

If you already use a predefined CSS theme on the page, a corresponding SVG theme is applied automatically. Otherwise, you need to apply the SVG theme.

You can also create custom SVG themes.

Apply a Theme

To apply an SVG theme to a single UI component, assign the theme's name to the UI component's theme property.

You can also pass the theme's name to the DevExpress.viz.currentTheme(theme) method to apply the theme to all SVG-based UI components on the page. If the UI components were created before the method call, use the DevExpress.viz.refreshTheme() method to refresh the styling settings.

jQuery
index.js
DevExpress.viz.currentTheme("material.blue.light");
DevExpress.viz.refreshTheme();
// ===== or when using modules =====
import { currentTheme, refreshTheme } from "devextreme/viz/themes";

currentTheme("material.blue.light");
refreshTheme();
Angular
app.component.ts
import { currentTheme, refreshTheme } from "devextreme/viz/themes";

currentTheme("material.blue.light");
refreshTheme();
Vue
App.vue
import { currentTheme, refreshTheme } from "devextreme/viz/themes";

currentTheme("material.blue.light");
refreshTheme();
React
App.js
import { currentTheme, refreshTheme } from "devextreme/viz/themes";

currentTheme("material.blue.light");
refreshTheme();

Create a Custom Theme

You can define several custom SVG themes and switch between them. The following code declares a custom theme called myTheme:

JavaScript
var customTheme = {
    name: 'myTheme',
    barGauge: { /* BarGauge configuration */ },
    bullet: { /* Bullet configuration */ },
    chart: { /* Chart configuration */ },
    funnel: { /* Funnel configuration */ },
    gauge: { /* CircularGauge and LinearGauge configuration */ },
    map: { /* VectorMap configuration */ },
    pie: { /* PieChart configuration */ },
    polar: { /* PolarChart configuration */ },
    rangeSelector: { /* RangeSelector configuration */ },
    sankey: { /* Sankey configuration */ },
    sparkline: { /* Sparkline configuration */ },
    treeMap: { /* TreeMap configuration */ }
};
NOTE
  • Particular properties cannot be used in themes. Such properties have a corresponding note in their description, for example, dataSource.

  • If you declare commonSeriesSettings properties, specify the name of the series. For instance, PieChart settings should be configured inside the pie object:

    JavaScript
    var customTheme = {
        name: 'myTheme',
        pie: { 
            // ...
            commonSeriesSettings: {
                pie: {
                    // ...
                }
            }
        }
    };

You should use the DevExpress.viz.registerTheme(customTheme, baseTheme) method to register the custom theme. Pass the name of a predefined theme as the baseTheme argument. This theme complements the custom theme if specific properties are absent in the latter. In the following code, Generic Light is used as the base theme:

jQuery
index.js
DevExpress.viz.registerTheme(customTheme, "generic.light");
// ===== or when using modules =====
import { registerTheme } from "devextreme/viz/themes";

registerTheme(customTheme, "generic.light");
Angular
app.component.ts
import { registerTheme } from "devextreme/viz/themes";

registerTheme(customTheme, "generic.light");
Vue
App.vue
import { registerTheme } from "devextreme/viz/themes";

registerTheme(customTheme, "generic.light");
React
App.js
import { registerTheme } from "devextreme/viz/themes";

registerTheme(customTheme, "generic.light");

Next, use the theme's name (myTheme) to apply the theme.