Handle no color support in React Color picker component

4 Jan 202418 minutes to read

The ColorPicker component supports no color functionality. By clicking the no color tile from palette, the selected color becomes empty and considered as no color has been selected from color picker.

Default no color

To achieve this, set noColor property as true.

In the following sample, the first tile of the color palette represents the no color tile. By clicking the no color tile you can achieve the above functionalities.

import { ColorPickerComponent } from '@syncfusion/ej2-react-inputs';
import * as React from "react";
import * as ReactDOM from "react-dom";
import { useEffect } from "react";
function App() {
    let preview;
    function onChange(args) {
        preview.style.backgroundColor = args.currentValue.hex;
        preview.textContent = args.currentValue.hex ? args.currentValue.hex : 'No color';
    }
    useEffect(() => {
        preview = document.getElementById('preview');
        preview.style.backgroundColor = '#ba68c8';
        preview.textContent = '#ba68c8';
    }, []);
    return (<div id='container'>
        <div className='wrap'>
            <div id='preview'/>
            <h4>Select Color</h4>
            <ColorPickerComponent id='colorpicker' value='#ba68c8' mode='Palette' noColor={true} showButtons={false} modeSwitcher={false} change={onChange}/>
        </div>
        </div>);
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));
import { ColorPickerComponent, ColorPickerEventArgs } from '@syncfusion/ej2-react-inputs';
import * as React from "react";
import * as ReactDOM from "react-dom";
import { useEffect } from "react";

function App() {
    let preview: HTMLElement;
    function onChange (args: ColorPickerEventArgs): void {
        preview.style.backgroundColor = args.currentValue.hex;
        preview.textContent = args.currentValue.hex ? args.currentValue.hex : 'No color';
    }

    useEffect(() => {
        preview = document.getElementById('preview') as HTMLElement;
        preview.style.backgroundColor = '#ba68c8';
        preview.textContent = '#ba68c8';
    }, []);

    return (
        <div id='container'>
        <div className='wrap'>
            <div id='preview'/>
            <h4>Select Color</h4>
            <ColorPickerComponent id='colorpicker' value='#ba68c8' mode='Palette' noColor={true} showButtons={false} modeSwitcher={false} change={onChange}/>
        </div>
        </div>
    );
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));

If the noColor property is enabled, make sure to disable the modeswitcher property.

Custom no color

The following sample show the color palette with custom no color option.

import * as React from "react";
import * as ReactDOM from "react-dom";
import { ColorPickerComponent, PaletteTileEventArgs, ColorPickerEventArgs } from '@syncfusion/ej2-react-inputs';
import { SplitButtonComponent } from '@syncfusion/ej2-react-splitbuttons';

function App() {
    let preview;
    let splitBtn;
    let colorPicker;

    let presets = {
        'custom': ['#f44336', '#e91e63', '#9c27b0', '#673ab7', '#2196f3', '#03a9f4', '#00bcd4', '#009688', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107']
    };

    function beforeTileRender(args) {
        args.element.classList.add('e-custom-tile');
    }

    function onChange (args) {
        preview = document.getElementById('preview');
        document.querySelector(".e-split-btn .e-picker-icon").style.borderBottomColor = args.currentValue.hex;
        preview.style.backgroundColor = args.currentValue.hex;
        preview.textContent = args.currentValue.hex;
        if (splitBtn.element.getAttribute("aria-expanded")) {
            splitBtn.toggle();
            splitBtn.element.focus();
        }
    }

    function onCreated() {
        preview = document.getElementById('preview');
        preview.style.backgroundColor = '#ba68c8';
        preview.textContent = '#ba68c8';
        document.getElementById('no-color').onclick = () => {
            //sets color picker value property to null
            colorPicker.setProperties({ 'value': '' }, true);
            document.querySelector('.e-split-btn .e-picker-icon').style.borderBottomColor = 'transparent';
            preview.textContent = 'No color';
            preview.style.backgroundColor = 'transparent';
        }
    }

    return (
        <div id='container'>
        <div className='wrap'>
            <ul id="target">
                <li className="e-item e-palette-item">
                    <ColorPickerComponent id='colorpicker' ref={(scope) => { colorPicker = scope; }} value='#f44336' mode='Palette' inline={true} columns={4} presetColors={presets} showButtons={false} modeSwitcher={false} beforeTileRender={beforeTileRender} change={onChange} created={onCreated}></ColorPickerComponent>
                </li>
                <li className="e-item" id="no-color">
                    <span className="e-menu-icon e-nocolor"></span>
                    No color
                </li>
            </ul>
            <div>
                <div id='preview'></div>
                <h4>Select color</h4>
                <SplitButtonComponent id='splitbtn' iconCss='e-cp-icons e-picker-icon' target='#target' ref={(scope) => { splitBtn = scope; }}></SplitButtonComponent>
            </div>
        </div>
        </div>
    );
}
export default App;
ReactDOM.render(<App />, document.getElementById('element'));
import * as React from "react";
import * as ReactDOM from "react-dom";
import { ColorPickerComponent, PaletteTileEventArgs, ColorPickerEventArgs } from '@syncfusion/ej2-react-inputs';
import { SplitButtonComponent } from '@syncfusion/ej2-react-splitbuttons';

function App() {
    let preview: HTMLElement;
    let splitBtn: SplitButtonComponent;
    let colorPicker: ColorPickerComponent;

    let presets: { [key: string]: string[] } = {
        'custom': ['#f44336', '#e91e63', '#9c27b0', '#673ab7', '#2196f3', '#03a9f4', '#00bcd4', '#009688', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107']
    };

    function beforeTileRender(args: PaletteTileEventArgs): void {
        args.element.classList.add('e-custom-tile');
    }

    function onChange (args: ColorPickerEventArgs): void {
        preview = document.getElementById('preview') as HTMLElement;
        (document.querySelector(".e-split-btn .e-picker-icon") as HTMLElement).style.borderBottomColor = args.currentValue.hex;
        preview.style.backgroundColor = args.currentValue.hex;
        preview.textContent = args.currentValue.hex;
        if (splitBtn.element.getAttribute("aria-expanded")) {
            splitBtn.toggle();
            splitBtn.element.focus();
        }
    }

    function onCreated(): void {
        preview = document.getElementById('preview') as HTMLElement;
        preview.style.backgroundColor = '#ba68c8';
        preview.textContent = '#ba68c8';
        document.getElementById('no-color')!.onclick = (): void => {
            //sets color picker value property to null
            colorPicker.setProperties({ 'value': '' }, true);
            (document.querySelector('.e-split-btn .e-picker-icon') as HTMLElement).style.borderBottomColor = 'transparent';
            preview.textContent = 'No color';
            preview.style.backgroundColor = 'transparent';
        }
    }

    return (
        <div id='container'>
        <div className='wrap'>
            <ul id="target">
                <li className="e-item e-palette-item">
                    <ColorPickerComponent id='colorpicker' ref={(scope) => { colorPicker = scope as ColorPickerComponent; }} value='#f44336' mode='Palette' inline={true} columns={4} presetColors={presets} showButtons={false} modeSwitcher={false} beforeTileRender={beforeTileRender} change={onChange} created={onCreated}></ColorPickerComponent>
                </li>
                <li className="e-item" id="no-color">
                    <span className="e-menu-icon e-nocolor"></span>
                    No color
                </li>
            </ul>
            <div>
                <div id='preview'></div>
                <h4>Select color</h4>
                <SplitButtonComponent id='splitbtn' iconCss='e-cp-icons e-picker-icon' target='#target' ref={(scope) => { splitBtn = scope as SplitButtonComponent; }}></SplitButtonComponent>
            </div>
        </div>
        </div>
    );
}

export default App;
ReactDOM.render(<App />, document.getElementById('element'));
#loader {
    color: #008cff;
    font-family: 'Helvetica Neue', 'calibiri';
    font-size: 14px;
    height: 40px;
    left: 45%;
    position: absolute;
    top: 45%;
    width: 30%;
}

@font-face {
font-family: 'paint';
src:
url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAAKAIAAAwAgT1MvMj0gSRIAAAEoAAAAVmNtYXDnEOdVAAABiAAAADZnbHlmIZD+uwAAAcgAAADMaGVhZBKhhHQAAADQAAAANmhoZWEHjANrAAAArAAAACRobXR4B+j/8wAAAYAAAAAIbG9jYQBmAAAAAAHAAAAABm1heHABDgBKAAABCAAAACBuYW1ln6hzswAAApQAAAINcG9zdEkLMmUAAASkAAAANgABAAADUv9qAFoEAP/z//4D6gABAAAAAAAAAAAAAAAAAAAAAgABAAAAAQAAAZfc6F8PPPUACwPoAAAAANfSn9kAAAAA19Kf2f/z//wD6gPhAAAACAACAAAAAAAAAAEAAAACAD4AAgAAAAAAAgAAAAoACgAAAP8AAAAAAAAAAQP0AZAABQAAAnoCvAAAAIwCegK8AAAB4AAxAQIAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABA5wDnAANS/2oAWgPhAJYAAAABAAAAAAAABAAAAAPo//MAAAACAAAAAwAAABQAAwABAAAAFAAEACIAAAAEAAQAAQAA5wD//wAA5wD//wAAAAEABAAAAAEAAAAAAAAAZgAAAAL/8//8A+oD4QAKAD0AAAEWBgceATc1JiQHJTMmNjceARcVJx4BBx4BFQ4BIiYnNDY3PgEvAS4BIw4BBwEGHgI3AT4BLwE1LgEnDgEDeiRlCgulCxP+8RT+GyYDQFxOZQwTBQEDDxEBJzonAREOCQkPJQ4cDBcdAf6oG1a3nx8BWQ4RHKADeG1oWwHTLHVwYVmL6Kx1BHEqfwYFqWUHEx4tDAocEx0nJx0RHgoVUDQpDgsBFAH+px2guFUaAVkNOiCgCXnhCAWOAAAAAAAAEgDeAAEAAAAAAAAAAQAAAAEAAAAAAAEABQABAAEAAAAAAAIABwAGAAEAAAAAAAMABQANAAEAAAAAAAQABQASAAEAAAAAAAUACwAXAAEAAAAAAAYABQAiAAEAAAAAAAoALAAnAAEAAAAAAAsAEgBTAAMAAQQJAAAAAgBlAAMAAQQJAAEACgBnAAMAAQQJAAIADgBxAAMAAQQJAAMACgB/AAMAAQQJAAQACgCJAAMAAQQJAAUAFgCTAAMAAQQJAAYACgCpAAMAAQQJAAoAWACzAAMAAQQJAAsAJAELIHBhaW50UmVndWxhcnBhaW50cGFpbnRWZXJzaW9uIDEuMHBhaW50Rm9udCBnZW5lcmF0ZWQgdXNpbmcgU3luY2Z1c2lvbiBNZXRybyBTdHVkaW93d3cuc3luY2Z1c2lvbi5jb20AIABwAGEAaQBuAHQAUgBlAGcAdQBsAGEAcgBwAGEAaQBuAHQAcABhAGkAbgB0AFYAZQByAHMAaQBvAG4AIAAxAC4AMABwAGEAaQBuAHQARgBvAG4AdAAgAGcAZQBuAGUAcgBhAHQAZQBkACAAdQBzAGkAbgBnACAAUwB5AG4AYwBmAHUAcwBpAG8AbgAgAE0AZQB0AHIAbwAgAFMAdAB1AGQAaQBvAHcAdwB3AC4AcwB5AG4AYwBmAHUAcwBpAG8AbgAuAGMAbwBtAAAAAAIAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgECAQMADHBhaW50LWJ1Y2tldAAAAAA=) format('truetype');
font-weight: normal;
font-style: normal;
}

.e-cp-icons {
 font-family: 'paint' !important;
speak: none;
font-size: 55px;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}

/* Preview area styles */
#preview {
  border: 1px solid;
  height: 40px;
  line-height: 40px;
  width: 100%;
}

.wrap {
  margin: 0 auto;
  width: 300px;
  text-align: center;
}

/* ColorPicker customization */
.e-dropdown-popup ul#target {
  padding: 0;
}

.e-dropdown-popup ul .e-item.e-palette-item {
  height: auto;
  padding: 0;
}

.e-btn-icon.e-picker-icon {
  border-bottom-color: #f44336;
  border-bottom-style: solid;
  border-bottom-width: 3px;
}

/* Picker icon */
.e-btn-icon.e-picker-icon::before {
  content: '\e700';
}

/* No color li styles */
.e-dropdown-popup ul .e-item .e-menu-icon.e-nocolor {
  height: 22px;
  margin-top: 8px;
  width: 22px;
  background: transparent url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNnB4IiBoZWlnaHQ9IjZweCIgdmlld0JveD0iMCAwIDYgNiIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4KICAgIDwhLS0gR2VuZXJhdG9yOiBTa2V0Y2ggNTAgKDU0OTgzKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Hcm91cCA5PC90aXRsZT4KICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPgogICAgPGRlZnM+PC9kZWZzPgogICAgPGcgaWQ9IlBhZ2UtMSIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9Ikdyb3VwLTkiPgogICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlLTExIiBmaWxsPSIjRTBFMEUwIiB4PSIwIiB5PSIwIiB3aWR0aD0iMyIgaGVpZ2h0PSIzIj48L3JlY3Q+CiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUtMTEtQ29weS0yIiBmaWxsPSIjRkZGRkZGIiB4PSIwIiB5PSIzIiB3aWR0aD0iMyIgaGVpZ2h0PSIzIj48L3JlY3Q+CiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUtMTEtQ29weSIgZmlsbD0iI0ZGRkZGRiIgeD0iMyIgeT0iMCIgd2lkdGg9IjMiIGhlaWdodD0iMyI+PC9yZWN0PgogICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlLTExLUNvcHktMyIgZmlsbD0iI0UwRTBFMCIgeD0iMyIgeT0iMyIgd2lkdGg9IjMiIGhlaWdodD0iMyI+PC9yZWN0PgogICAgICAgIDwvZz4KICAgIDwvZz4KPC9zdmc+');
}

/* Tile customization */
.e-container .e-palette .e-tile.e-custom-tile {
  height: 24px;
  width: 24px;
  margin: 4px;
}

h4, #preview {
    font-family: 'Helvetica Neue', 'Helvetica', 'Arial', 'sans-serif';
    font-size: 14px;
}