Démo interactive
Chaque carte reproduit une situation où un sélecteur classique sortait de l'écran ou se faisait couper. Ici la popup est rendue dans body en position: fixed et reste toujours visible.
1. Input texte, palette complète
Ouverture au focus ou par la pastille. Palette thème, palette web, historique et case transparente.
2. Lignes d'un tableau : input hidden + pastille
La couleur identifie la ligne. Le champ hidden part avec le formulaire, la pastille est le seul contrôle visible. Palette réduite à 9 couleurs.
| Dupont Frères | Devis n° 2041 | |
| Garage Marin | Facture n° 887 | |
| Atelier Lenoir | Commande n° 1290 |
3. Dans une boîte overflow: hidden
Un widget positionné en absolute serait coupé par la bordure pointillée.
4. Dans une zone scrollable
La popup suit l'ancre pendant le défilement et bascule au-dessus quand la place manque en dessous.
5. Mode inline
Sur un élément qui n'est pas un input, la palette est rendue en place et reste visible.
6. API
Cible : le picker n° 1. Historique partagé entre toutes les instances de la page.
🎯 Pourquoi une palette fermée ?
Un sélecteur à dégradé propose 16 millions de couleurs, et deux utilisateurs ne choisissent jamais la même. Ce composant propose volontairement une palette limitée et fixe : chaque couleur est exacte et reproductible. Une ligne, une étiquette ou un statut garde donc la même teinte partout où il apparaît et se reconnaît d'un coup d'œil. Le jeu de couleurs devient un vocabulaire, pas du bruit.
Couleurs exactes
Toujours #rrggbb en minuscules, tirées d'une liste connue. Pas de « presque rouge ».
Identifiables
Dix colonnes, des nuances contrastées : l'œil retrouve la couleur sans lire sa valeur.
Votre propre nuancier
customTheme remplace la palette par la liste de votre charte, 10 par ligne.
Saisie libre possible
Le champ texte accepte toute couleur CSS valide tapée au clavier, si vous l'autorisez.
📦 Installation
npm install @synapxlab/colorpicker
Ou via CDN (ESM, aucune installation) :
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@synapxlab/colorpicker/dist/style.css">
<script type="module">
import { ColorPicker } from 'https://cdn.jsdelivr.net/npm/@synapxlab/colorpicker/dist/colorpicker.es.js';
</script>
⚡ Démarrage rapide
import { ColorPicker, locales } from '@synapxlab/colorpicker';
import '@synapxlab/colorpicker/style';
const cp = new ColorPicker(document.querySelector('#color'), {
strings: locales.fr,
transparentColor: true,
onChange(color) {
console.log('choisi', color); // '#4f81bd'
},
});
<link rel="stylesheet" href="node_modules/@synapxlab/colorpicker/dist/style.css">
<script src="node_modules/@synapxlab/colorpicker/dist/colorpicker.umd.cjs"></script>
<script>
const { ColorPicker } = window.SynapxColorPicker;
ColorPicker.init('[role="colorpicker"]', { showOn: 'button' });
</script>
📖 Options
new ColorPicker(element, options) — un <input> texte ou hidden ouvre une popup ; tout autre élément reçoit la palette en mode inline.
| Option | Type | Défaut | Description |
|---|---|---|---|
color | string | null | input.value | Valeur initiale |
customTheme | string[] | — | Remplace la palette thème par votre liste, 10 par ligne. Les entrées invalides sont écartées |
showOn | 'focus' | 'button' | 'both' | 'manual' | 'both' | Ce qui ouvre la popup. Un input hidden passe toujours par la pastille |
hideButton | boolean | false | Pas de pastille, l'input seul ouvre |
displayIndicator | boolean | true | Indicateurs « couleur courante / survolée » en bas de la popup |
transparentColor | boolean | false | Ajoute une case transparente hachurée |
transparentValue | string | 'transparent' | Valeur stockée pour transparent. evol utilisait '#0000ffff', accepté en compatibilité |
history | boolean | true | Historique partagé entre tous les pickers (28 entrées, sans doublon) |
initialHistory | string[] | — | Alimente l'historique au départ |
defaultPalette | 'theme' | 'web' | 'theme' | Page affichée à l'ouverture |
strings | object | string | locales.en | Libellés : objet partiel, locales.fr, ou la chaîne CSV d'evol. Le français est choisi seul si un ancêtre porte lang="fr" |
container | HTMLElement | document.body | Parent de la popup. Passez un <dialog> ouvert pour rester dans le top-layer |
zIndex | number | 10000 | Au-dessus des modales Bootstrap (1055) |
offset | number | 4 | Espace ancre → popup (px) |
viewportMargin | number | 8 | Distance minimale aux bords de l'écran (px) |
placement | 'auto' | 'bottom' | 'top' | 'auto' | Côté préféré. auto = dessous, ou dessus s'il y a plus de place |
onChange, onHover, onOpen, onClose | function | — | Rappels équivalents aux événements ci-dessous |
🔔 Événements & méthodes
Les événements sont des CustomEvent qui remontent depuis l'élément, avec detail.color et detail.instance. Un choix déclenche aussi les événements natifs input puis change sur l'input : formulaires et frameworks réagissent sans code supplémentaire.
input.addEventListener('colorpicker:change', (e) => console.log(e.detail.color));
input.addEventListener('colorpicker:hover', (e) => preview.style.background = e.detail.color);
input.addEventListener('colorpicker:open', () => {});
input.addEventListener('colorpicker:close', () => {});
| Méthode | Rôle |
|---|---|
getValue() / setValue(color, { silent }) | Lit ou écrit la couleur. silent n'émet aucun événement |
show() / hide() / toggle() / isOpen() | Pilotage de la popup |
enable() / disable() / isDisabled() | Verrouillage |
clear() | Ferme et vide la valeur |
destroy() | Retire tout le DOM ajouté et les écouteurs, l'input retrouve sa place |
ColorPicker.init(selector, options) | Instancie sur chaque élément trouvé |
ColorPicker.get(element) | Instance attachée à un élément |
ColorPicker.history | Historique partagé, lecture seule |
📐 Positionnement
La popup n'est jamais dans l'arbre de l'input : elle est ajoutée à body en position: fixed, donc aucun parent overflow, transform ou contain ne peut la couper. Sa position se calcule dans le repère de la fenêtre :
- par défaut sous l'ancre, alignée à gauche ;
- pas la place dessous et plus de place dessus → au-dessus ;
- recalée horizontalement pour rester à
viewportMargindes bords ; - fenêtre plus petite que la popup → hauteur contrainte, la popup défile en interne ;
- recalcul au scroll, au redimensionnement et quand la popup change de taille.
Le calcul est une fonction pure exportée, testable sans DOM :
import { computePosition } from '@synapxlab/colorpicker';
computePosition(
{ top: 690, left: 1200, width: 20, height: 20 }, // ancre en bas à droite
{ width: 220, height: 260 }, // popup
{ width: 1280, height: 720 }, // fenêtre
);
// → { top: 426, left: 1052, placement: 'top' }
zIndex 10000 et le rendu dans body suffisent. Pour un <dialog> natif, passez-le en container pour que la popup reste dans le top-layer.
🔁 Migration depuis evol-colorpicker
Mêmes palettes, mêmes pages, mêmes options : la migration se résume à retirer jQuery UI et à remplacer l'appel du widget.
$("[role='colorpicker']").colorpicker({
showOn: "button",
displayIndicator: false,
customTheme: ["#f44336", "#ff9800", "white", "black"],
strings: "Couleur,base,Plus,Moins,Palette,",
});
$(input).colorpicker("val", value);
$(input).on("change.color", (e, color) => …);
ColorPicker.init('[role="colorpicker"]', {
showOn: 'button',
displayIndicator: false,
customTheme: ['#f44336', '#ff9800', 'white', 'black'],
strings: 'Couleur,base,Plus,Moins,Palette,', // la chaîne CSV reste acceptée
});
ColorPicker.get(input).setValue(value);
input.addEventListener('colorpicker:change', (e) => …);
| evol-colorpicker | @synapxlab/colorpicker |
|---|---|
.colorpicker(options) | new ColorPicker(el, options) ou ColorPicker.init(sel, options) |
.colorpicker("val", c) | setValue(c) |
.colorpicker("showPalette") / "hidePalette" | show() / hide() |
"enable" / "disable" / "clear" / "destroy" | mêmes noms de méthodes |
change.color / mouseover.color | colorpicker:change / colorpicker:hover |
transparent = '#0000ffff' | 'transparent', ou transparentValue: '#0000ffff' |
classes .evo-* | classes .sxcp-*, variables --sxcp-* |