svelte-gradient-editor Svelte Themes

Svelte Gradient Editor

Svelte Gradient Editor

*** Check the DEMO ***

Standalone Svelte 5 gradient editor component with a typed model API..

Like it? I'd appreciate the support :)

Description

The best Gradient Editor you'll find for Svelte. We use this package on our project chatstyle.gg, go check it out! Everything below this line isn't handwritten and optimized for da clankers, have fun!

*** Check the DEMO ***

It keeps two representations of the same gradient synchronized:

  • A CSS gradient string for direct use in background-image
  • A structured GradientModel object for application logic

Install

npm install svelte-gradient-editor-component

Peer dependency:

  • svelte ^5.0.0

Quick Start

<script lang="ts">
  import { GradientEditor } from 'svelte-gradient-editor-component';
  import type { GradientEditorMessages, GradientModel } from 'svelte-gradient-editor-component';

  let value = 'linear-gradient(90deg, #ff0000 0%, #0000ff 100%)';
  let model: GradientModel | undefined;

  const messages: GradientEditorMessages = {
    gradientMode: 'Gradient type',
    linear: 'Linear',
    conic: 'Conic',
    radial: 'Radial',
    angle: 'Angle',
    stopAriaLabel: ({ position, index, total }) =>
      `Color stop ${index + 1} of ${total} at ${position}%`
  };
</script>

<GradientEditor
  bind:value
  bind:model
  angleDecimals={0}
  positionDecimals={1}
  {messages}
  on:change={(event) => {
    console.log(event.detail.value);
    console.log(event.detail.model);
  }}
/>

What The Component Does

  • Supports editing linear-gradient(...), conic-gradient(...), and radial-gradient(...)
  • Keeps value and model synchronized after every change
  • Lets users add, move, recolor, and delete gradient stops
  • Lets users switch between linear, conic, and radial gradients
  • Lets users edit linear/conic angle and radial shape
  • Uses the same stop editor abstraction for all supported gradient modes
  • Emits normalized output rather than preserving unsupported input syntax verbatim

Public Exports

The package entry point exports:

import {
  GradientEditor,
  cloneGradientModel,
  defaultGradientModel,
  modelSignature,
  normalizeHexColor,
  normalizeModel,
  parseGradient,
  serializeGradient
} from 'svelte-gradient-editor-component';

import type {
  ConicGradientModel,
  GradientEditorMessages,
  GradientModel,
  GradientStop,
  LinearGradientModel,
  RadialGradientModel
} from 'svelte-gradient-editor-component';

Component API

Props

Prop Type Default Purpose
value string '' Bound CSS gradient string. The component normalizes it to a supported canonical form.
model GradientModel | undefined undefined Bound typed model. If provided, this takes precedence over value.
showValue boolean false Shows the current serialized gradient string inside the component UI.
angleDecimals number 0 Decimal precision for linear angle editing and emitted angle values.
positionDecimals number 0 Decimal precision for stop position editing, dragging, adding, and emitted values.
messages GradientEditorMessages {} Overrides built-in English labels and ARIA text.

Event

change

type GradientEditorChangeDetail = {
  value: string;
  model: GradientModel;
};

The component emits change on every committed editor update.

Bindings

  • bind:value Canonical CSS gradient string suitable for background-image
  • bind:model Canonical structured model synchronized with value

Types

type GradientStop = {
  id: string;
  color: string;
  position: number;
};

type LinearGradientModel = {
  type: 'linear';
  angle: number;
  stops: GradientStop[];
};

type ConicGradientModel = {
  type: 'conic';
  angle: number;
  stops: GradientStop[];
};

type RadialGradientModel = {
  type: 'radial';
  shape: 'circle' | 'ellipse';
  stops: GradientStop[];
};

type GradientModel = LinearGradientModel | ConicGradientModel | RadialGradientModel;
type GradientEditorMessages = {
  gradientMode?: string;
  linear?: string;
  conic?: string;
  radial?: string;
  radialShape?: string;
  ellipse?: string;
  circle?: string;
  angleDial?: string;
  angle?: string;
  gradientTrack?: string;
  gradientStops?: string;
  editGradientStop?: string;
  stopColor?: string;
  position?: string;
  deleteStop?: string;
  stopAriaLabel?: (input: {
    position: number;
    index: number;
    total: number;
    color: string;
  }) => string;
};

Behavior Contract

This section is intended to be explicit enough for both humans and coding agents.

Source Of Truth

  • If model is passed, the component uses model as the incoming source of truth.
  • If model is not passed, the component parses value.
  • Internally, the component normalizes the gradient before writing back to value or model.

Normalization

  • Colors are normalized to lowercase 6-digit hex when possible.
  • Stop positions are clamped to 0..100.
  • Stops are sorted by position.
  • At least 2 stops always exist after normalization.
  • Missing stop positions are distributed automatically.
  • Linear and conic angles are normalized to a 0..360 degree representation.
  • Radial shape is normalized to either 'circle' or 'ellipse'.

Precision

By default, the component edits and emits integers.

<GradientEditor bind:value bind:model />

Enable decimals explicitly:

<GradientEditor bind:value bind:model angleDecimals={1} positionDecimals={2} />

Rules:

  • angleDecimals and positionDecimals should be non-negative integers.
  • Invalid, negative, or non-finite values fall back to 0.
  • Precision affects component interactions and emitted values.
  • Helper functions like parseGradient() and serializeGradient() keep their own API and are not driven by component prop precision.

Supported Input

Supported gradient families:

  • linear-gradient(...)
  • conic-gradient(...)
  • radial-gradient(...)

Supported linear direction syntax:

  • Degree syntax such as 90deg
  • Named directions such as to right, to top left

Supported radial syntax:

  • Shapes circle and ellipse

Supported conic syntax:

  • conic-gradient(#ff0000 0%, #0000ff 100%)
  • conic-gradient(from 45deg, #ff0000 0%, #0000ff 100%)

Unsupported CSS Features

The package does not preserve full CSS gradient syntax.

Examples of unsupported or only partially supported input:

  • Linear angle units other than degrees, such as turn
  • Conic positioning such as at center
  • Radial positioning such as at center
  • Radial sizing keywords such as closest-side or cover
  • Non-hex color syntax in parsed input, such as named colors or rgb(...)

Conic support in v1 is intentionally angle-only. Parsed conic gradients round-trip canonically as conic-gradient(from Xdeg, ...).

When unsupported input is encountered, the parser falls back to the closest supported model or to a safe default gradient.

User Interactions

The editor supports these built-in interactions:

  • Click the gradient track to add a stop
  • Drag a stop handle to move it
  • Click a stop to open its popup editor
  • Edit stop color with the color input
  • Edit stop position with the numeric input
  • Delete the selected stop from the popup
  • Press Delete or Backspace outside editable fields to remove the selected stop
  • Press Escape to close the stop popup
  • Switch between linear and radial modes
  • Switch between linear, conic, and radial modes
  • Drag the angle dial or use keyboard input on it

Guardrails:

  • A gradient cannot be reduced below 2 stops
  • Deletion is disabled when only 2 stops remain

Helper Functions

parseGradient(value)

Parses a supported CSS gradient string into a normalized GradientModel.

const model = parseGradient('linear-gradient(to right, #111111 0%, #eeeeee 100%)');

serializeGradient(model)

Serializes a GradientModel into canonical CSS.

const css = serializeGradient({
  type: 'conic',
  angle: 45,
  stops: [
    { id: 'a', color: '#ffaa00', position: 0 },
    { id: 'b', color: '#220044', position: 100 }
  ]
});

normalizeModel(model)

Returns a normalized clone of a model:

  • stop positions clamped and sorted
  • colors normalized
  • invalid radial shapes corrected
  • conic output canonicalized to from <angle>deg
  • angle rounded to the helper's built-in precision

defaultGradientModel(overrides?)

Creates a valid default model.

Defaults:

  • linear gradients default to angle 90
  • conic gradients default to angle 0
  • radial gradients default to shape 'ellipse'
  • default stops are #ff7a18 0% and #5b4dff 100%

cloneGradientModel(model)

Returns a normalized deep clone of the gradient model.

modelSignature(model)

Returns a JSON string signature of the normalized model. Useful for stable equality checks after normalization.

normalizeHexColor(value)

Accepts 3-digit or 6-digit hex values and returns normalized lowercase 6-digit hex, or null for unsupported input.

Messages And Localization

All user-facing text is consumer-controlled from code. The package does not require any specific i18n library.

<script lang="ts">
  import { GradientEditor } from 'svelte-gradient-editor-component';
  import type { GradientEditorMessages } from 'svelte-gradient-editor-component';

  const messages: GradientEditorMessages = {
    gradientMode: 'Modo de degradado',
    linear: 'Lineal',
    conic: 'Conico',
    radial: 'Radial',
    radialShape: 'Forma radial',
    ellipse: 'Elipse',
    circle: 'Circulo',
    angleDial: 'Control de angulo',
    angle: 'Angulo',
    gradientTrack: 'Pista de degradado',
    gradientStops: 'Paradas del degradado',
    editGradientStop: 'Editar parada',
    stopColor: 'Color',
    position: 'Posicion',
    deleteStop: 'Eliminar parada',
    stopAriaLabel: ({ position, index, total, color }) =>
      `Parada ${index + 1} de ${total}: ${color} en ${position}%`
  };
</script>

<GradientEditor bind:value bind:model {messages} />

Theming

The component ships with self-contained styles. Override its CSS custom properties on the component or any parent container.

<div
  style="
    --gradient-editor-text: #e5e7eb;
    --gradient-editor-border: rgba(229, 231, 235, 0.2);
    --gradient-editor-accent: #60a5fa;
  "
>
  <GradientEditor bind:value bind:model />
</div>

Supported CSS variables:

  • --gradient-editor-bg
  • --gradient-editor-panel
  • --gradient-editor-border
  • --gradient-editor-text
  • --gradient-editor-muted
  • --gradient-editor-accent
  • --gradient-editor-shadow
  • --gradient-editor-radius

AI Agent Notes

If you are generating code against this package, assume these rules:

  • GradientEditor is the only component export.
  • value and model are both writable bindings.
  • model wins over value when both are provided.
  • Emitted change.detail always contains both value and model.
  • The component only supports linear, conic, and radial gradients.
  • Canonical output uses degree-based linear/conic gradients and hex stop colors.
  • Do not rely on unsupported CSS syntax surviving a parse/serialize round-trip.
  • Do not assume decimal stop positions unless positionDecimals is set.
  • Do not assume decimal angles unless angleDecimals is set.
  • The package expects Svelte 5.

Local Development

npm install
npm run dev
npm run test
npm run check
npm run build

Commands:

  • npm run dev starts the local Vite demo
  • npm run test runs the Vitest suite
  • npm run check runs svelte-check
  • npm run build builds the library package into dist/

Top categories

Loading Svelte Themes