npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

customizable-gradient-picker

v1.1.0

Published

[TRY INTERACTIVE DEMO >>](https://customizable-gradient-picker.vercel.app/)

Readme

TRY INTERACTIVE DEMO >>

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

  • Supports linear-gradient, radial-gradient, and conic-gradient
  • Controlled API via gradient and onChange
  • 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-picker

Requirements

  • 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-gradient
  • radial-gradient
  • conic-gradient

Default internal prefixes:

  • linear-gradient: no prefix
  • radial-gradient: circle at center
  • conic-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-square
  • hue-slider
  • alpha-slider
  • alpha-input
  • eye-dropper
  • stop-position
  • stop-delete
  • gradient-slider
  • gradient-formats
  • gradient-preview
  • gradient-string
  • angle-input
  • hex-input
  • hex-preview
  • rgba-input
  • rgba-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

  • store
  • stops
  • activeStopId
  • activeStopPosition
  • angle
  • format
  • isDragging
  • recentlyUsedColors
  • libraryColors
  • hex
  • rgba
  • rgbaString
  • gradientString
  • opacity

Actions

  • setR
  • setG
  • setB
  • setA
  • setHex
  • setAngle
  • setFormat
  • setOpacity
  • setStopColor
  • setActiveStop
  • setStopPosition
  • setLibraryColors
  • setRecentlyUsedColors
  • addStop
  • addColorToLibrary
  • addColorToRecentlyUsed
  • removeStop
  • removeColorFromLibrary
  • removeColorFromRecentlyUsed
  • convertColor

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

  • GradientPicker
  • useGradient

UI primitives

  • ColorSquare
  • HueSlider
  • AlphaSlider
  • AlphaInput
  • AngleInput
  • DeleteStop
  • EyeDropper
  • GradientSlider
  • PickGradientFormats
  • GradientPreview
  • GradientString
  • HexInput
  • HexPreview
  • RgbaInput
  • RgbaPreview
  • StopPosition

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.