JavaScript Color Picker

@lemonadejs/color · ✓ 18 contract checks · framework-agnostic · zero dependencies

<Color /> — color picker on the Modal primitive (v5 architecture).

Faithful port of @lemonadejs/color: a Grid tab (the material palette matrix, custom palettes supported, the picked cell marked with a checkmark) and a Spectrum tab (canvas gradient, drag to sample pixels), Reset/Done bar, popup built ON Modal exactly as v5 built on @lemonadejs/modal (headerless, absolute, auto-adjust, no focus steal), optional text input toggle with the full v5 keyboard system (ArrowUp/Down opens, Enter commits, Escape closes) and focusout close.

v5 → v6 mapping: value → bind; closeOnChange → closeonchange; input: ‘auto’ → type=“input” (the block renders its own input — adopting an external element was dropped, incompatible with by-value blocks); type: ‘inline’ keeps its meaning (panel without a popup, selection commits immediately since the Done bar is a popup affordance); @lemonadejs/tabs → internal lm-color-tabs strip (no Tabs block in v6). onclose(origin): ‘select’ | ‘button’ | ‘escape’ | ‘focusout’ | ‘api’.

Example

live
import { html } from 'lemonadejs';
import Color from '@lemonadejs/color';

const App = (props, { state }) => {
    const brand = state('#2563eb');
    const accent = state('#f59e0b');

    return html`<div style="display:grid;gap:12px;max-width:320px">
        <${Color} type="input" bind="${brand}" placeholder="Brand color" />
        <${Color} type="input" bind="${accent}" closeonchange placeholder="Accent (closes on pick)"
            palette="${[
                ['#ef4444', '#f97316', '#f59e0b', '#84cc16', '#10b981'],
                ['#06b6d4', '#3b82f6', '#8b5cf6', '#ec4899', '#64748b'],
            ]}" />
        <div style="${() => 'padding:16px;border-radius:8px;color:#fff;background:' + brand.value + ';border-left:8px solid ' + accent.value}">
            Brand <b>${brand}</b> with accent <b>${accent}</b>
        </div>
    </div>`;
};

Installation

npm install @lemonadejs/color
import Color from '@lemonadejs/color';
import '@lemonadejs/color/style.css';

Three deployment forms, one component:

html`<${Color} />`                       // by value (no registration)
setComponents({ Color });               // then <Color /> by name anywhere
createWebComponent(Color);              // <lm-color> in plain HTML/any framework

Props

Every declared prop arrives as a live state — pass a value for a snapshot or a state for a two-way live wire. Attribute strings are coerced to the declared type.

PropTypeDefaultDescription
bindstringTwo-way bound value. .set() fires onchange; plain assignment is silent. the picked color (v5: value)
namestring''form field name — root reflects el.value (form-associated)
palettearraystring[][] matrix — a flat string[] becomes one row
typestring''” (popup via api)
placeholderstring''input placeholder (v5)
aria-labelstring''
closeonchangebooleanfalsev5: closeOnChange — picking commits + closes immediately

Events

All event names are lowercase (the platform convention — LJS-305 warns otherwise).

  • onopen — popup opened
  • onclose — popup closed (origin)
  • onchange — the picked color changed (user-initiated)

API

import { ref } from 'lemonadejs';
const color = ref();
html`<${Color} ref="${color}" />`;
// color.current.open(...)  ·  color.current.close(...)  ·  color.current.isClosed(...)  ·  color.current.reset(...)  ·  color.current.setValue(...)  ·  color.current.getValue(...)
  • open()
  • close()
  • isClosed()
  • reset()
  • setValue()
  • getValue()

Styling

All classes follow the lm-color-* convention; visual variants are data-* attributes on the root. Override freely — there is no styling engine to fight.

Contract

The machine-readable schema ships with the package:

import contract from '@lemonadejs/color/contract.json';

verify.json carries the conformance proof produced by verify(Color).

Looking for the v5 plugin? See the archived v5 documentation.