Skip to content

Color picker

The ColorPicker component is a powerful UI element designed for seamless color selection. It is ideal for applications such as design tools, image editors, or any interface requiring color customization.

As part of the complex components in Gameface UI, the ColorPicker combines multiple basic components to deliver advanced functionality. It enables users to adjust hue, saturation, brightness, and transparency, while providing a color preview area for visual feedback.

Internally, the component utilizes the following basic components:

  • XYSlider for adjusting brightness and saturation.
  • Slider for controlling hue and alpha (transparency).
  • Segment for toggling the color preview mode between HEX and RGBA.

To use the ColorPicker component, simply import and render it as shown below:

import ColorPicker from '@components/Complex/ColorPicker/ColorPicker';
const App = () => {
return (
<ColorPicker />
);
};
export default App;
Prop NameTypeDefaultDescription
styleJSX.CSSProperties{}Inline styles to apply directly to the color picker’s wrapper element.
classstring""Additional CSS classes to apply to the color picker’s wrapper element.
refColorPickerRef | undefinedundefinedA reference to the component, providing access to its methods and the underlying HTML element.
valuestringrgba(255, 0, 0, 1)Initial value of the color picker. Accepts colors as strings in HEX or RGBA format.
size'S' | 'M' | 'L' | 'XL''L'Sets the size of the color picker. The size affects the overall dimensions and font sizes within the component. Ideal for quick customization.
onChange(value: ColorData) => voidundefinedA callback function triggered whenever the color changes. It can be used to retrieve the updated color value.
onActionRecord<string, (scope?: string, ...args: any[]) => void>undefinedAllows you to add custom navigation action handlers to the color picker. See the Navigation component documentation for details.
anchorstring | HTMLElementundefinedLinks navigation to another element. When the anchor element is focused, the color picker’s actions will execute. Can be a CSS selector or HTMLElement.

To interact with the ColorPicker programmatically, you can use the ColorPickerRef interface. This interface provides properties and methods to access and manipulate the component’s state.

PropertyTypeDescription
elementHTMLDivElementA reference to the color picker’s root HTML element, useful for DOM access or styling.
MethodParametersReturn ValueDescription
valueNone{rgba: string, hex: string}Retrieves the currently selected color value from the color picker into rgba and hex format.
changeColornewColor: stringvoidUpdates the color picker programmatically with a new color. This method accepts color strings in either RGBA or HEX format, which are automatically converted to ColorData internally.
PropertyTypeDescription
hnumberRepresents the hue of the color (0-360).
snumberRepresents the saturation of the color (0-100).
vnumberRepresents the brightness of the color (0-100).
anumberRepresents the alpha (transparency) of the color (0-1).

To simplify color format conversions, utility methods are available for translating between HSVA, RGBA, and HEX. These methods can be imported from @components/Complex/ColorPicker/colorPickerUtils:

import { RGBAOrHEXToHSVA, RGBAToHSVA, parseHSVAColor } from "@components/Complex/ColorPicker/colorPickerUtils";

RGBAOrHEXToHSVA(color: string) => ColorData

Section titled “RGBAOrHEXToHSVA(color: string) => ColorData”

Converts a color string in RGBA or HEX format to ColorData. The method automatically detects the input format and performs the conversion.

import { RGBAOrHEXToHSVA } from "@components/Complex/ColorPicker/colorPickerUtils";
RGBAOrHEXToHSVA('rgba(0, 0, 0, 0.5)'); // Returns ColorData: { h: 0, s: 0, v: 0, a: 0.5 }
RGBAOrHEXToHSVA('#00000080'); // Returns ColorData: { h: 0, s: 0, v: 0, a: 0.5 }

Converts an RGBA color string to ColorData.

import { RGBAToHSVA } from "@components/Complex/ColorPicker/colorPickerUtils";
RGBAToHSVA('rgba(0, 0, 0, 0.5)'); // Returns ColorData: { h: 0, s: 0, v: 0, a: 0.5 }

parseHSVAColor(color: ColorData) => string

Section titled “parseHSVAColor(color: ColorData) => string”

Converts ColorData to a color string in RGBA or HEX format.

import { parseHSVAColor } from "@components/Complex/ColorPicker/colorPickerUtils";
parseHSVAColor({ h: 0, s: 0, v: 0, a: 1 }); // Returns { rgba: 'rgba(0, 0, 0, 1)', hex: '#000000FF' }

To initialize the color picker with a value other than the default rgba(255, 0, 0, 1), use the value prop. This prop accepts color strings in either RGBA or HEX format. Internally, the component converts the provided value to HSVA format for internal processing.

import ColorPicker from '@components/Complex/ColorPicker/ColorPicker';
const App = () => {
return (
<ColorPicker value="rgba(0, 0, 0, 0.5)" />
// Or
<ColorPicker value="#00000080" />
);
};
export default App;

Programmatically changing the color picker value

Section titled “Programmatically changing the color picker value”

To update the color picker value programmatically, use the ref prop to access the component’s instance. The changeColor method allows you to set a new color. The method accepts string values in RGBA or HEX format, which are automatically converted to ColorData internally.

import ColorPicker from '@components/Complex/ColorPicker/ColorPicker';
const App = () => {
let colorPickerRef!: ColorPickerRef;
const changeColor = () => {
if (colorPickerRef) {
// Update the color to rgba(0, 0, 0, 0.5)
colorPickerRef.changeColor('rgba(0, 0, 0, 0.5)');
}
};
return (
<>
<ColorPicker ref={colorPickerRef} />
<button onClick={changeColor}>Change Color</button>
</>
);
};

To access the current value of the color picker, use the ref prop to obtain a reference to the component instance. This reference provides methods for interacting with the color picker.

The value method retrieves the current color in {rgba: string, hex: string} format. If you need the color in HSVA format, use the RGBAOrHEXToHSVA utility method to convert the rgba or hex string to ColorData which represents the color in hue, saturation, value, and alpha components.

import ColorPicker from '@components/Complex/ColorPicker/ColorPicker';
const App = () => {
let colorPickerRef!: ColorPickerRef;
const getColor = () => {
if (colorPickerRef) {
// Retrieve the current color value from the color picker
const color = colorPickerRef.value();
console.log(color); // Logs the color in RGBA and HEX format
// Example output: { rgba: 'rgba(0, 0, 0, 0.5)', hex: '#00000080' }
}
};
return (
<>
<ColorPicker ref={colorPickerRef} />
<button onClick={getColor}>Get Color</button>
</>
);
};

To respond to color changes in the ColorPicker, use the onChange prop. This prop accepts a callback function that receives the updated color value as an argument. The value is provided in ColorData format, which includes hue, saturation, brightness, and alpha components.

Because the provided value of the onChange callback is in ColorData format, you can use the parseHSVAColor utility method to convert it to a string in either RGBA or HEX format if needed.

import ColorPicker, { ColorData } from '@components/Complex/ColorPicker/ColorPicker';
import { parseHSVAColor } from '@components/Complex/ColorPicker/colorPickerUtils';
const App = () => {
const handleColorChange = (color: ColorData) => {
console.log('Color changed:', color);
// Example output: { h: 0, s: 0, v: 0, a: 0.5 }
// Convert to RGBA or HEX string if needed
const rgbaString = parseHSVAColor(color).rgba; // 'rgba(0, 0, 0, 0.5)'
const hexString = parseHSVAColor(color).hex; // '#00000080'
console.log('RGBA:', rgbaString);
console.log('HEX:', hexString);
};
return (
<ColorPicker onChange={handleColorChange} />
);
};

The ColorPicker component can be tailored to fit your application’s design by using the style and class props. These props allow you to apply custom styles and CSS classes to the wrapper element of the color picker.

import ColorPicker from '@components/Complex/ColorPicker/ColorPicker';
const App = () => {
return (
<ColorPicker
style={{ width: '300px', height: '300px' }}
class="custom-color-picker"
/>
);
};
export default App;

Extending the Color Picker With Navigation 2.0.0

Section titled “Extending the Color Picker With Navigation ”2.0.0

The ColorPicker component can be extended to work with the Navigation component to allow for keyboard or gamepad navigation.

Since the ColorPicker is built using basic components like XYSlider, Slider and Segment , which are compatible with the Navigation system, you can wrap the ColorPicker in a Navigation component to enable navigation support.

To achieve this, follow these steps:

  1. Make sure the ColorPicker is a descendant of a Navigation component in your component tree.
  2. Wrap the components in the ColorPicker you wish to enable navigation for with the Navigation.Area component.
  3. Optionally, add focus styles for all components that will be navigable for visual indication.

In this example we will modify the ColorPicker component to include Navigation.Area around the internal components that we want to be navigable. The component’s internal navigation setup will handle the interactions out of the box!

ColorPicker.tsx
const ColorPicker: ParentComponent<ColorPickerProps> = (props) => {
// Existing color picker code...
return (
<div ref={element}
class={className()}
style={inlineStyles()}
use:forwardEvents={props}
use:forwardAttrs={props}>
<Navigation.Area name="color-picker" focused>
<XYSlider ref={xySliderRef} value={{ x: initialValue.s, y: 100 - initialValue.v }} class={styles.XYSlider} onChange={handleXYChange}>
<XYSlider.Background style={XYSliderBackground()} />
17 collapsed lines
<XYSlider.Handle class={styles['XYSlider-handle']} style={{ "background-color": selectedColorNonTransparent() }}></XYSlider.Handle>
</XYSlider>
<Slider ref={hueSliderRef} min={0} max={360} value={initialValue.h} onChange={handleHueChange} class={styles['hue-slider']}>
<Slider.Track class={styles['hue-slider-track']} />
<Slider.Fill class={styles['slider-fill']}></Slider.Fill>
<Slider.Handle class={styles['slider-handle']} style={{ background: selectedColorHue() }} />
</Slider>
<Slider ref={alphaSliderRef} value={initialValue.a * 100} onChange={handleAlphaChange} class={styles['alpha-slider']}>
<Slider.Track class={styles['alpha-slider-track']} style={{ 'background-image': `linear-gradient(to right,transparent 0% , ${selectedColorNonTransparent()} 100% )` }} />
<Slider.Fill class={styles['slider-fill']}></Slider.Fill>
<Slider.Handle class={styles['slider-handle']} style={{ background: selectedColor() }} />
</Slider>
<Segment class={styles.segment} onChange={(value) => setSelectedFormat(value)}>
<Segment.Indicator class={styles['segment-indicator']}></Segment.Indicator>
<Segment.Button class={styles['segment-button']} selected value="hex">HEX</Segment.Button>
<Segment.Button class={styles['segment-button']} value="rgba">RGBA</Segment.Button>
</Segment>
</Navigation.Area>
<div class={styles['color-preview-wrapper']}>
<div class={styles['color-preview']}>
<div class={styles['color-preview-box']} style={{ 'background-color': selectedColor() }}></div>
</div>
<TextInput class={styles['color-preview-text']} readonly value={colorTextValue()} />
</div>
</div >
);
}

For the visual focus indication, in this example we add a border to the slider handles and a box-shadow to the segment when the components receive focus.

Since there are multiple sliders in the ColorPicker’s components, we can create a SCSS mixin to handle the focus styles for the slider handles. Here’s how you can implement it:

ColorPicker.module.scss
@mixin handle-focus($slider-name) {
&:focus {
.#{$slider-name} {
border: 0.2vmax solid rgb(197, 197, 197);
}
}
}
.XYSlider {
5 collapsed lines
width: 100%;
border: none;
margin-bottom: 0.5em;
height: 10em;
@include handle-focus('XYSlider-handle');
5 collapsed lines
&-handle {
width: 1.5em;
height: 1.5em;
}
}
.hue-slider,
.alpha-slider {
7 collapsed lines
width: 85%;
height: 0.75em;
padding: 0;
margin: 0;
margin-top: 0.5em;
margin-bottom: 0.5em;
border-radius: 0.5em;
@include handle-focus('slider-handle');
}
.segment {
margin-top: 0.5em;
margin-bottom: 0.5em;
&:focus {
box-shadow: 0 0 0.5vmax rgba(0, 0, 0, 0.2);
}
}