customizable-gradient-picker
v1.1.0
Published
[TRY INTERACTIVE DEMO >>](https://customizable-gradient-picker.vercel.app/)
Readme
Customizable Gradient Picker
A composable React gradient picker for building anything from a minimal editor to a full-featured gradient design panel.
This library is built around a controlled CSS gradient string and a flexible set of UI primitives. You can use the picker as a simple drop-in component, or compose your own interface with the provided controls and hook.
Contents
- Features
- Installation
- Requirements
- Quick start
- How it works
- Supported gradient formats
- Basic usage patterns
- GradientPicker API
- Available grid nodes
- Using the hook
- useGradient return value
- Stop structure
- Common operations
- Exported components
- Styling and customization
- Browser notes
- Practical notes
- Next.js example
- When to use this library
- Summary
Features
- Supports
linear-gradient,radial-gradient, andconic-gradient - Controlled API via
gradientandonChange - Composable UI primitives
- Optional grid-based layout rendering
- Shared internal store support
- Hook for custom controls and advanced integrations
- Class-based styling customization
- Custom icon overrides
- Works well in modern React and Next.js applications
Installation
npm install customizable-gradient-pickerRequirements
- React 18+
- React DOM 18+
If you use Next.js App Router, render the picker inside a client component.
Quick start
'use client';
import { useState } from 'react';
import {
GradientPicker,
ColorSquare,
HueSlider,
AlphaSlider,
StopPosition,
GradientSlider,
} from 'customizable-gradient-picker';
export default function Example() {
const [gradient, setGradient] = useState(
'linear-gradient(90deg, rgb(39, 109, 35) 0%, rgba(163, 0, 255, 1) 100%)',
);
return (
<GradientPicker gradient={gradient} onChange={setGradient}>
<div style={{ display: 'grid', gap: 12 }}>
<ColorSquare />
<HueSlider />
<AlphaSlider />
<StopPosition />
<GradientSlider />
</div>
</GradientPicker>
);
}How it works
The library accepts a CSS gradient string as input and emits a new CSS gradient string every time the user changes the gradient.
That means you can:
- store the gradient in React state
- save it in a database
- preview it directly in CSS
- share the same value across different parts of your UI
Supported gradient formats
linear-gradientradial-gradientconic-gradient
Default internal prefixes:
linear-gradient: no prefixradial-gradient:circle at centerconic-gradient:from 90deg at 50% 50%
Basic usage patterns
1. Compose the picker manually
Use this when you want full control over layout and markup.
<GradientPicker gradient={gradient} onChange={setGradient}>
<div className="my-layout">
<ColorSquare />
<HueSlider />
<AlphaSlider />
<StopPosition />
<GradientSlider />
<GradientString />
</div>
</GradientPicker>2. Render from a grid definition
Use this when you want the library to render a layout from predefined node names.
<GradientPicker
gradient={gradient}
onChange={setGradient}
grid={[
'color-square',
'hue-slider',
'alpha-slider',
{
className: 'row',
children: ['stop-position', 'gradient-formats'],
},
'gradient-slider',
'gradient-string',
]}
/>GradientPicker API
type GradientPickerProps =
| {
gradient: string;
onChange: (gradient: string) => void;
updateDelay?: number;
wrapperClassName?: string;
childrenProps?: ChildrenProps;
store?: GradientPickerStore;
grid: Grid;
}
| {
gradient: string;
onChange: (gradient: string) => void;
updateDelay?: number;
wrapperClassName?: string;
childrenProps?: ChildrenProps;
store?: GradientPickerStore;
children: React.ReactNode;
};Props
gradient
The current CSS gradient string.
onChange
Called with the updated CSS gradient string.
updateDelay
Optional delay for gradient output updates. Default is 0.
wrapperClassName
Custom class name for the root picker wrapper.
store
Optional external store. Useful when you want built-in components and your own custom UI to share the same picker state.
children
Manual rendering mode. Use this when you want to fully control layout.
grid
Grid rendering mode. Use this when you want the library to generate the layout from known node names.
childrenProps
Optional props passed into built-in grid nodes.
Available grid nodes
You can use the following names inside grid:
color-squarehue-slideralpha-slideralpha-inputeye-dropperstop-positionstop-deletegradient-slidergradient-formatsgradient-previewgradient-stringangle-inputhex-inputhex-previewrgba-inputrgba-preview
Example with childrenProps:
<GradientPicker
gradient={gradient}
onChange={setGradient}
grid={['gradient-formats', 'gradient-slider', 'gradient-string']}
childrenProps={{
gradientFormats: {
allowedFormats: ['linear-gradient', 'radial-gradient'],
},
gradientString: {
onCopyClick: () => console.log('Copied'),
},
}}
/>Using the hook
Use useGradient when you want to build a custom editor, connect outside controls, or directly read and manipulate picker state.
'use client';
import { useMemo } from 'react';
import {
GradientPicker,
ColorSquare,
HueSlider,
AlphaSlider,
GradientSlider,
StopPosition,
useGradient,
} from 'customizable-gradient-picker';
export default function Example() {
const {
store,
gradientString,
stops,
activeStopId,
hex,
rgba,
angle,
format,
setHex,
setAngle,
setFormat,
setActiveStop,
setStopPosition,
addStop,
removeStop,
} = useGradient(
'linear-gradient(90deg, rgb(39, 109, 35) 0%, rgba(163, 0, 255, 1) 100%)',
next => {
console.log('New gradient:', next);
},
);
const activeStop = useMemo(
() => stops.find(stop => stop.id === activeStopId) ?? null,
[stops, activeStopId],
);
return (
<div style={{ display: 'grid', gap: 16 }}>
<GradientPicker store={store} gradient={gradientString} onChange={() => {}}>
<div style={{ display: 'grid', gap: 12 }}>
<ColorSquare />
<HueSlider />
<AlphaSlider />
<StopPosition />
<GradientSlider />
</div>
</GradientPicker>
<div>
<div>Format: {format}</div>
<div>Angle: {angle}</div>
<div>HEX: {hex}</div>
<div>RGBA: {rgba}</div>
<div>Active stop: {activeStop?.id ?? 'none'}</div>
</div>
</div>
);
}useGradient return value
The hook returns both state and actions.
State
storestopsactiveStopIdactiveStopPositionangleformatisDraggingrecentlyUsedColorslibraryColorshexrgbargbaStringgradientStringopacity
Actions
setRsetGsetBsetAsetHexsetAnglesetFormatsetOpacitysetStopColorsetActiveStopsetStopPositionsetLibraryColorssetRecentlyUsedColorsaddStopaddColorToLibraryaddColorToRecentlyUsedremoveStopremoveColorFromLibraryremoveColorFromRecentlyUsedconvertColor
Stop structure
Each stop returned from the hook is normalized into a predictable shape:
type StopItem = {
position: number;
id: string;
hex: string;
rgbaString: string;
rgba: {
r: number;
g: number;
b: number;
a: number;
};
opacity: number;
};Common operations
Set the active stop
setActiveStop('stop2');Change a stop color
setStopColor('stop2', 'rgba(255, 0, 0, 1)');Move a stop
setStopPosition('stop2', 75);Add a stop
addStop(50, 'rgba(255, 255, 255, 1)');Remove a stop
removeStop('stop2');Change gradient format
setFormat('radial-gradient');Change angle
setAngle(135);Convert between color formats
const hex = convertColor('rgba', 'hex', 'rgba(255, 0, 0, 1)');
const rgba = convertColor('hex', 'rgba', 'FF0000');Exported components
Core
GradientPickeruseGradient
UI primitives
ColorSquareHueSliderAlphaSliderAlphaInputAngleInputDeleteStopEyeDropperGradientSliderPickGradientFormatsGradientPreviewGradientStringHexInputHexPreviewRgbaInputRgbaPreviewStopPosition
Styling and customization
Most components expose classNames props so you can control their styles without rewriting their logic.
Example:
<HueSlider
classNames={{
wrapper: 'my-hue-wrapper',
thumb: 'my-hue-thumb',
canvas: 'my-hue-canvas',
}}
/>Custom gradient format button styles
<PickGradientFormats
classNames={{
wrapper: 'formats',
button: {
base: 'format-button',
activeBase: 'format-button-active',
icon: 'format-icon',
},
buttons: {
'linear-gradient': {
base: 'format-linear',
},
'radial-gradient': {
base: 'format-radial',
},
'conic-gradient': {
base: 'format-conic',
},
},
}}
/>Custom icons
Some controls let you replace built-in icons with your own components.
<PickGradientFormats
icons={{
'linear-gradient': MyLinearIcon,
'radial-gradient': MyRadialIcon,
'conic-gradient': MyConicIcon,
}}
/>Other components such as AngleInput, GradientString, EyeDropper, HexInput, and RgbaInput also support icon overrides.
Browser notes
Clipboard support
GradientString uses the Clipboard API for copying the generated gradient string.
EyeDropper support
EyeDropper depends on the browser EyeDropper API. If the browser does not support it, that control will not be available as expected.
Practical notes
The library is controlled
Even though the picker has an internal store, the main usage model is controlled through gradient and onChange.
Use the hook for advanced editors
If you need presets, custom side panels, linked inputs, recent colors, or full control over behavior, useGradient is the right entry point.
Minimum stop count
The hook does not remove stops when only two remain.
HEX input support
setHex supports common HEX lengths such as 3, 4, 6, and 8 characters.
Recently used colors limit
Recently used colors are trimmed to the latest 24 entries.
Next.js example
'use client';
import { useState } from 'react';
import {
GradientPicker,
ColorSquare,
HueSlider,
AlphaSlider,
GradientSlider,
StopPosition,
GradientString,
} from 'customizable-gradient-picker';
export default function GradientEditor() {
const [gradient, setGradient] = useState(
'linear-gradient(90deg, rgba(255, 126, 95, 1) 15%, rgba(254, 180, 123, 1) 85%)',
);
return (
<div style={{ display: 'grid', gap: 16 }}>
<div
style={{
height: 180,
borderRadius: 16,
background: gradient,
}}
/>
<GradientPicker gradient={gradient} onChange={setGradient}>
<div style={{ display: 'grid', gap: 12 }}>
<ColorSquare />
<HueSlider />
<AlphaSlider />
<StopPosition />
<GradientSlider />
<GradientString />
</div>
</GradientPicker>
</div>
);
}When to use this library
This library is a good fit when you need:
- a gradient picker with a controlled API
- composable building blocks instead of a fixed UI
- support for multiple CSS gradient types
- a custom editor with shared state
- a picker that can scale from simple inputs to a full design tool
Summary
Customizable Gradient Picker is designed for teams that need flexibility. You can start with the built-in controls, then gradually move toward a fully custom experience without changing the underlying gradient model.
