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

ngx-gradient-picker

v1.2.0

Published

A modern Angular gradient picker component with draggable color stops, angle picker, and support for linear/radial gradients

Readme

ngx-gradient-picker

A modern Angular gradient picker component with draggable color stops, circular angle picker, and full two-way binding support.

npm version License: MIT Angular Bundle Size CI

📺 Live Demo

✨ Features

  • Draggable color stops with smooth animations
  • Click to add new stops on the gradient bar
  • Drag down to delete stops
  • Double-click to open native color picker
  • Single stop = solid color - one stop automatically becomes a solid color
  • Circular angle picker for linear gradients
  • 6 gradient types: Linear, Radial, Conic, Repeating-Linear, Repeating-Radial, Repeating-Conic
  • CSS parsing - auto-detect gradient type, angle, and stops from CSS
  • Mobile-friendly - bottom-sheet mode for popover, touch-optimized
  • Angular Signals for optimal performance
  • Standalone components - no module needed
  • Two-way binding with [(palette)], [(angle)], [(type)]
  • Works with Reactive Forms
  • Fully customizable dimensions and CSS
  • 🚫 Zero external dependencies - only Angular core

Installation

npm install ngx-gradient-picker

or with yarn:

yarn add ngx-gradient-picker

or with pnpm:

pnpm add ngx-gradient-picker

Quick Start

Basic Usage

import { Component, signal } from '@angular/core';
import { GradientPickerComponent, ColorStop, createColorStop } from 'ngx-gradient-picker';

@Component({
  selector: 'app-example',
  standalone: true,
  imports: [GradientPickerComponent],
  template: `
    <ngx-gradient-picker
      [(palette)]="palette"
      [(angle)]="angle"
      [(type)]="type"
      [width]="350"
      [paletteHeight]="32"/>
  `
})
export class ExampleComponent {
  palette = signal<ColorStop[]>([
    createColorStop(0, '#ff6b6b'),
    createColorStop(0.5, '#4ecdc4'),
    createColorStop(1, '#45b7d1')
  ]);
  angle = signal(90);
  type = signal<GradientType>('linear');
}

GradientType

type GradientType = 
  | 'linear' 
  | 'radial' 
  | 'conic'
  | 'repeating-linear'
  | 'repeating-radial'
  | 'repeating-conic';

Popover Mode

Perfect for forms and compact UIs. By default, the picker automatically adapts to the device:

import { GradientPickerPopoverComponent } from 'ngx-gradient-picker';

@Component({
  imports: [GradientPickerPopoverComponent],
  template: `
    <!-- Auto mode (default): mobile = bottom-sheet, desktop = popover -->
    <ngx-gradient-picker-popover
      [(palette)]="palette"
      [(angle)]="angle"/>
  `
})

Position Options

| Position | Behavior | |----------|----------| | 'auto' (default) | Auto-detects device: mobile/touch → bottom-sheet, desktop → popover | | 'bottom' / 'top' / 'left' / 'right' | Force popover at specified position | | 'bottom-sheet' | Force bottom-sheet mode (full-width modal) |

<!-- Force popover mode even on mobile -->
<ngx-gradient-picker-popover [position]="'bottom'"/>

<!-- Force bottom-sheet even on desktop -->
<ngx-gradient-picker-popover [position]="'bottom-sheet'"/>

CSS Auto-Detection

Parse any CSS gradient string and extract its type, angle, and color stops:

import { parseGradientCSS } from 'ngx-gradient-picker';

const css = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
const config = parseGradientCSS(css);
// config = { type: 'linear', angle: 135, stops: [...] }

// Then apply to your picker:
palette.set(config.stops);
angle.set(config.angle);
type.set(config.type);

Get CSS Output

import { Component, viewChild } from '@angular/core';
import { GradientPickerComponent, paletteToCSS } from 'ngx-gradient-picker';

@Component({
  template: `
    <ngx-gradient-picker #picker [(palette)]="palette" [(angle)]="angle"/>
    <div [style.background]="gradientCSS">Preview</div>
  `
})
export class ExampleComponent {
  picker = viewChild<GradientPickerComponent>('picker');
  
  // Option 1: Use the component method
  get gradientCSS() {
    return this.picker()?.getGradientCSS() ?? '';
  }
  
  // Option 2: Use the utility function
  get gradientCSS2() {
    return paletteToCSS(this.palette(), this.angle(), 'linear');
  }
}

With Reactive Forms

The component implements ControlValueAccessor, so it works directly with Angular forms:

import { Component, signal, inject } from '@angular/core';
import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
import { GradientPickerComponent, ColorStop, createColorStop } from 'ngx-gradient-picker';

@Component({
  standalone: true,
  imports: [ReactiveFormsModule, GradientPickerComponent],
  template: `
    <form [formGroup]="form">
      <!-- formControlName binds the CSS output directly -->
      <ngx-gradient-picker
        formControlName="gradient"
        [(palette)]="palette"
        [(angle)]="angle"/>
      
      <div [style.background]="form.get('gradient')?.value">
        Preview
      </div>
    </form>
  `
})
export class FormComponent {
  private fb = inject(FormBuilder);
  
  palette = signal<ColorStop[]>([
    createColorStop(0, '#667eea'),
    createColorStop(1, '#764ba2')
  ]);
  angle = signal(90);
  
  // The CSS string is automatically synced to the form control
  form = this.fb.group({
    gradient: ['']
  });
}

API Reference

GradientPickerComponent

The component implements ControlValueAccessor - the form value is the CSS gradient string.

| Input/Output | Type | Default | Description | |--------------|------|---------|-------------| | [(palette)] | ColorStop[] | [] | Two-way binding for color stops | | [(angle)] | number | 90 | Gradient angle (0-360 deg) | | [(type)] | GradientType | 'linear' | Gradient type (see types above) | | [width] | number | 300 | Picker width in pixels | | [paletteHeight] | number | 24 | Gradient bar height | | [minStops] | number | 1 | Minimum color stops (1 allows solid colors) | | [maxStops] | number | 50 | Maximum color stops | | (stopSelect) | EventEmitter<ColorStop> | - | Emitted when a stop is selected | | formControlName | string | - | Binds CSS output to form control |

GradientPickerPopoverComponent

| Input/Output | Type | Default | Description | |--------------|------|---------|-------------| | [(palette)] | ColorStop[] | [] | Two-way binding for color stops | | [(angle)] | number | 90 | Gradient angle | | [width] | number | 300 | Picker width | | [position] | PopoverPosition | 'auto' | Position mode (see table above) |

type PopoverPosition = 'top' | 'bottom' | 'left' | 'right' | 'bottom-sheet' | 'auto';

ColorStop Interface

interface ColorStop {
  id: string;       // Unique identifier
  offset: number;   // Position (0 to 1)
  color: string;    // Hex color value (#rrggbb)
  opacity?: number; // Optional opacity (0 to 1)
}

Helper Functions

import { 
  createColorStop, 
  paletteToCSS,
  parseGradientCSS,
  generateStopId,
  sortStopsByOffset,
  generateGradientCSS
} from 'ngx-gradient-picker';

// Create a new color stop
const stop = createColorStop(0.5, '#ff0000');
// { id: 'stop-xxx', offset: 0.5, color: '#ff0000', opacity: 1 }

// Generate CSS from palette
const css = paletteToCSS(palette, 90, 'linear');
// 'linear-gradient(90deg, #ff0000 0%, #00ff00 100%)'

// Parse CSS to get gradient config (auto-detection)
const config = parseGradientCSS('linear-gradient(45deg, #ff6b6b 0%, #4ecdc4 100%)');
// { type: 'linear', angle: 45, stops: [...] }

🎨 Solid Color Support

When only one color stop is present, the picker automatically outputs a solid color instead of a gradient:

// Single stop = solid color output
const palette = [createColorStop(0, '#ff6b6b')];
const css = paletteToCSS(palette, 90, 'linear');
// Returns: '#ff6b6b' (not 'linear-gradient(...)')

This is enabled by default (minStops="1"). To enforce at least 2 stops (gradient only), set minStops to 2:

<ngx-gradient-picker
  [(palette)]="palette"
  [minStops]="2" />

User Interactions

| Action | Effect | |--------|--------| | Click on gradient bar | Add new color stop | | Drag a stop horizontally | Reposition the stop | | Drag a stop down | Delete the stop (if > minStops) | | Double-click a stop | Open native color picker | | Drag angle picker | Change gradient angle | | Click type button | Cycle between linear/radial/conic | | Click repeat button | Toggle repeating mode |

🎨 CSS Customization

Override these CSS classes to customize the appearance:

| Class | Description | |-------|-------------| | .gradient-picker-container | Main wrapper with background, padding, border-radius | | .gradient-picker-header | Header containing type picker and angle picker | | .gradient-picker-body | Body containing palette and color stops | | .color-stop-marker | The circular color stop marker | | .palette-svg | The gradient preview bar | | .angle-picker-container | Container for the angle dial | | .dial | The circular dial element | | .type-picker-container | Container for type toggle buttons | | .type-toggle | Type toggle button (linear/radial/conic) | | .repeat-toggle | Repeat mode toggle button | | .popover-trigger | The button that opens the popover | | .popover-content | The popover container | | .popover-backdrop | Backdrop overlay (bottom-sheet mode) |

Example customization:

::ng-deep .gradient-picker-container {
  background: #1a1a2e;
  border-radius: 16px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}

::ng-deep .color-stop-marker {
  width: 20px;
  height: 20px;
  border-width: 3px;
}

Angular Compatibility

| ngx-gradient-picker | Angular | |---------------------|---------| | 1.x | 17.x, 18.x, 19.x, 20.x |

📦 Bundle Size

| Metric | Size | |--------|------| | FESM Bundle (unminified) | ~99 KB | | Gzipped (estimated) | ~16 KB |

Note on npm publishing best practices: Angular libraries are published unminified to npm. This is intentional because:

  • The consuming application's bundler (webpack, esbuild, vite) handles tree-shaking to remove unused code
  • The bundler's minifier optimizes all code together for better compression
  • Source maps remain accurate for debugging
  • Consumer build tools can apply their own optimizations

The final impact on your app will depend on which components you import and your bundler's optimization settings.

Demo

📺 Try the live demo

Contributing

Contributions are welcome! Please read our Contributing Guide for details on:

  • How to submit bug reports and feature requests
  • How to set up the development environment
  • Code style guidelines
  • Pull request process

License

MIT © Mikhaël GERBET