React Color Picker: HEX, RGB, HSL, Pipette und OKLCH

Ein React Color Picker wirkt wie eine Aufgabe fürs Wochenende, bis du aufschreibst, was Nutzer erwarten: ein Farbfeld zum Ziehen, eine Farbton-Leiste, ein Textfeld, in das eine Designerin #FC4C01 einfügt, RGB- oder HSL-Kanäle für den Entwickler, der in Zahlen denkt, Markenfarben als Swatches, Deckkraft, eine Pipette, die eine Farbe aus dem Logo holt, Tastaturbedienung und etwas, das auf dem Smartphone funktioniert. Danach muss der Wert in einem Designsystem landen, das in Tailwind CSS v4 in OKLCH geschrieben ist. Dieser Guide zeigt jeden Teil am Color Picker von Wingo UI. Wir bauen diese Bibliothek selbst, neutral sind wir also nicht. Externe Fakten sind mit ihrer Quelle verlinkt und datiert.
Was muss ein React Color Picker können?
Ein vollständiger Picker hat ein Feld für Sättigung und Helligkeit, eine Farbton-Leiste, Textfelder für HEX, RGB und HSL, vordefinierte Swatches, Tastaturbedienung auf jeder Fläche und ein Layout fürs Smartphone. Deckkraft und Pipette sind die beiden optionalen Teile. Kleine Bibliotheken wie react-colorful (opens in a new tab) (3,1 KB gzipped und ohne Abhängigkeiten, laut README im Oktober 2026) liefern dir die Flächen zum Ziehen und ein Hex-Feld, den Rest baust du selbst. Diese Checkliste gilt für jeden Farbwähler in React, egal welchen Weg du nimmst:
- Ein Feld für Sättigung und Helligkeit plus eine Farbton-Leiste. Das ist das HSV-Modell und der schnellste Weg, Farben zu erkunden.
- Textfelder für HEX, RGB und HSL. Leute fügen Werte aus Figma, einem Styleguide oder den DevTools ein. Jedes Eingabefeld eines React Color Pickers sollte eingefügten Text annehmen und Unsinn ablehnen, ohne die letzte gültige Farbe zu verlieren.
- Swatches, denn die meisten echten Entscheidungen lauten „eine unserer acht Markenfarben“.
- Deckkraft für Schatten und Overlays, standardmäßig aus.
- Eine Pipette, wo der Browser eine hat.
- Tastaturbedienung für das Farbfeld und die Leisten, nicht nur für die Textfelder.
- Ein Layout fürs Smartphone, denn ein 288px breites Popover lässt sich mit dem Daumen schlecht bedienen.
Hat shadcn/ui einen Color Picker?
Nein. Stand 16. Oktober 2026 listet die Komponentenseite von shadcn/ui (opens in a new tab) Popover, Slider, Input und Toggle Group, aber keinen Color Picker, und empfiehlt für Community-Komponenten das eigene Registry-Verzeichnis. Ein shadcn Color Picker entsteht also durch Komposition: ein Popover, Slider für Farbton und Alpha, eine eigene 2D-Fläche (Radix hat keinen 2D-Slider), ein Eingabefeld mit eigenem Parser und Buttons für die Swatches.
Die Komponente von Wingo UI ist genauso gebaut, auf Radix Popover und Radix Slider, und wird mit einer CLI im shadcn-Stil als Quellcode installiert. Die Dateien gehören also dir, du kannst sie lesen und ändern:
Der Befehl holt auch alles, was die Komponente importiert: Field für Label und Fehlermeldung, Drawer für das Sheet auf dem Smartphone, Segmented Control für den Umschalter HEX / RGB / HSL, Button und die kleinen Helfer, die sie mit dem Rest der Bibliothek teilt (Controllable State, Media Queries, Motion-Presets und Defaults über UIProvider).
Wie nutzt du den Color Picker in React?
Rendere ColorPicker mit einem Label und einem Wert. Er zeigt ein Eingabefeld, und ein Klick darauf öffnet ein Panel mit dem Farbfeld, der Farbton-Leiste, dem Format-Umschalter, den Eingabefeldern und 16 Standard-Swatches.
Zwei Callbacks sind hier wichtig. onValueChange feuert live beim Ziehen, höchstens einmal pro Animation Frame, damit eine Vorschau dem Daumen folgen kann. onValueCommit feuert, wenn die Änderung feststeht: beim Loslassen, bei Enter oder Blur in einem Textfeld, beim Tippen auf einen Swatch, bei einem Pick mit der Pipette, bei einer Taste im Farbfeld oder beim Fertig-Button im Sheet auf dem Smartphone. Speichere erst im zweiten Callback, sonst schickt ein einziges Ziehen Dutzende Requests. Die Prop name rendert ein verstecktes Eingabefeld, so liest ein natives Formular oder eine Server Action die Farbe mit formData.get("primary_color").
Probier es unten aus: Zieh im Farbfeld, wechsle dann zu RGB und tipp einen Wert ein. Ungültiger Text färbt das Feld rot, und der Wert springt zur letzten gültigen Farbe zurück.
$ npx wingo-ui@latest add color-pickerWie verhalten sich die Felder für HEX, RGB und HSL?
Die Prop format ("hex", "rgb" oder "hsl", Standard "hex") legt fest, welchen String der Picker ausgibt und welche Felder das Panel zuerst zeigt. Der Umschalter im Panel ändert nur, welche Felder sichtbar sind. Nutzer können also RGB-Kanäle eintippen, während dein State weiter Hex bekommt. Die Ausgabe hat immer genau diese Form: "#FC4C01", "rgb(252, 76, 1)" und "hsl(18, 99%, 50%)".
Ein paar Details ersparen dir Support-Tickets:
- Ein dreistelliger Hex-Wert wird erweitert,
F60ergibt also#FF6600. Das#ist optional. - ArrowUp und ArrowDown in einem Zahlenfeld ändern den Wert um 1, mit Shift um 10.
defaultValueundvaluenehmen jede Farbe an, die der Parser liest: Hex mit 3, 4, 6 oder 8 Stellen,rgb()/rgba(),hsl()/hsla()mit Kommas oder Leerzeichen und die Namen der 16 CSS-Grundfarben. Der Parser braucht kein Canvas und läuft deshalb auch auf dem Server.
Dieselben Umrechnungen sind für deinen eigenen Code exportiert. parseColor(text) gibt ein Hsva oder null zurück, und formatColor(hsva, format, alpha) macht daraus wieder einen String:
Wie fügst du Deckkraft und Markenfarben hinzu?
Schalte alpha ein, wenn Werte Transparenz brauchen. Das fügt eine Leiste und ein Feld für die Deckkraft hinzu. Hex wird unter 100% zu #RRGGBBAA, rgb und hsl werden immer zu rgba() / hsla(). So behält der String sein Format, während sich der Slider bewegt.
$ npx wingo-ui@latest add color-pickerFür eine Markenpalette übergibst du swatches. Der Standard ist das exportierte COLOR_PICKER_SWATCHES (16 Farben, erst Grautöne, dann Rot bis Pink). Du kannst es also erweitern oder ersetzen, und [] blendet die Reihe aus. Mit showInputs={false} verschwinden Textfelder, Format-Umschalter und Pipette. Übrig bleiben Farbfeld, Farbton-Leiste und deine Swatches:
Die Swatches sind eine Radio Group: ein Tab-Stopp, Pfeiltasten zum Wechseln (ArrowUp und ArrowDown springen eine Reihe mit 8 Farben weiter) und ein Ring, der zur gewählten Farbe gleitet.
Wie funktioniert die EyeDropper API in React?
Die EyeDropper API (opens in a new tab) öffnet die System-Pipette: new EyeDropper().open() liefert { sRGBHex }, sobald jemand auf ein Pixel klickt. MDN führt sie als experimentell, und sie läuft nur in sicheren Kontexten (Secure Contexts). Laut der Referenz von MDN zu open() (opens in a new tab) wird das Promise abgelehnt: mit AbortError bei Escape oder einem abgebrochenen Signal, mit NotAllowedError, wenn der Aufruf nicht aus einer Nutzergeste kommt, und mit InvalidStateError, wenn schon eine andere Pipette offen ist. Stand Oktober 2026 führt caniuse (opens in a new tab) Unterstützung in Chrome und Edge ab 95 und Opera ab 81 auf dem Desktop, aber keine in Safari, Firefox oder Chrome für Android.
Wenn du einen React Color Picker mit Eyedropper selbst baust, gehen oft drei Dinge schief:
window.EyeDropperwird beim Rendern gelesen. Das stürzt auf dem Server ab oder führt zu einem Hydration Mismatch. Prüf die API erst nach dem Mount.- In Safari erscheint ein Button, der nichts tut. Blende ihn aus, wo die API fehlt.
- Die System-Pipette bleibt offen, wenn dein Popover schließt. Gib
open()einAbortSignalmit und brich beim Unmount ab.
Eine minimale Version, die alle drei Fehler vermeidet:
Der Picker von Wingo UI macht intern dasselbe: Die Pipette erscheint nur, wo window.EyeDropper existiert, das Schließen des Panels bricht einen laufenden Pick ab, und das Popover ignoriert Klicks außerhalb, solange die System-Pipette offen ist. Der Klick, der ein Pixel wählt, schließt das Panel also nicht. Abschalten kannst du sie mit showEyeDropper={false}.
Wie passt ein React Color Picker zu OKLCH-Tokens in Tailwind v4?
Speichere die Farbe, die Nutzer wählen, als Hex und lass CSS daraus OKLCH ableiten. Die Standardpalette von Tailwind v4 ist in OKLCH geschrieben (--color-red-500: oklch(63.7% 0.237 25.331) in der Doku zu Farben (opens in a new tab), geprüft im Oktober 2026), während der Picker in sRGB arbeitet und sein Parser keine oklch()-Strings liest. Die beiden Hälften lassen sich sauber trennen:
- Hex ist das Speicherformat. Das gibt der Picker aus, das fügen Leute ein, und das liefert die EyeDropper API (
sRGBHex). - OKLCH wird in CSS abgeleitet. Relative Color Syntax rechnet beim Rendern um:
oklch(from #FC4C01 l c h)ist diese Farbe in OKLCH, und du kannst einen Kanal ändern, etwa die Helligkeit, und die übrigen beibehalten. Caniuse (opens in a new tab) führt Stand Oktober 2026 volle Unterstützung in Chrome und Edge 131, Safari 18 und Firefox 133.
Der kostenlose Helfer colorVars in @/lib/tones von Wingo UI macht genau das, und die Prop color von Button läuft durch ihn. Er erzeugt aus einem String fünf Tone-Variablen und wählt schwarzen oder weißen Text anhand der OKLCH-Helligkeit:
So kann eine vom Nutzer gewählte Farbe einen einzelnen Button mit <Button color={color}> umfärben oder zur Laufzeit den ganzen Brand-Tone, ohne Build-Schritt:
Jede Komponente mit tone="brand" und jede bg-brand-Utility im Wrapper übernimmt die neue Farbe. Eine Bedingung gibt es: Der Override erreicht die Utilities nur, wenn das Theme sie mit @theme inline { --color-brand: var(--brand); } verknüpft, und genau das tut die globals.css von Wingo UI. Mit normalem @theme wird var(--brand) einmal auf :root aufgelöst, und ein Wrapper, der --brand neu setzt, ändert für bg-brand nichts.
Willst du in deinem React Color Picker OKLCH-Werte anzeigen oder brauchst du die Zahlen für eine Token-Datei, dann rechne das RGB des Pickers in JavaScript mit den OKLab-Matrizen von Björn Ottosson (opens in a new tab) um:
Eine ehrliche Grenze: Hex kann nur sRGB beschreiben. Laut dem Release-Post zu Tailwind v4 (opens in a new tab) nutzt die OKLCH-Palette einen größeren Farbraum, damit die Farben kräftiger wirken, als sRGB es erlaubte. Wählst du eine dieser Farben auf einem P3-Bildschirm, bekommst du also den nächstliegenden sRGB-Hexwert, nicht den ursprünglichen Wert. Schreib Tokens mit erweitertem Farbraum von Hand in CSS und nutze den Picker für die Farben, die Nutzer wählen. Wie die Token-Ebenen zusammenspielen, erklärt unser Guide zu Design Tokens in Tailwind v4.
Ist der Color Picker per Tastatur bedienbar?
Ja. Das Farbfeld und die Leisten sind eigene Elemente mit role="slider", und alle reagieren auf Tasten:
- Enter, Space oder ArrowDown auf dem Trigger öffnen das Panel und setzen den Fokus ins Farbfeld.
- Im Farbfeld ändern ArrowLeft und ArrowRight die Sättigung um 1%, ArrowUp und ArrowDown die Helligkeit (mit Shift um 10%), PageUp und PageDown ändern die Helligkeit in Schritten von 10%, und Home und End springen auf keine oder volle Sättigung.
- Die Leisten für Farbton und Deckkraft reagieren auf die Pfeiltasten, Home und End.
- Escape schließt das Panel und gibt den Fokus an den Trigger zurück. Hat ein Textfeld eine noch nicht übernommene Eingabe, setzt das erste Escape sie zurück und lässt das Panel offen.
- Screenreader lesen am Trigger das Label samt Wert vor („Primärfarbe, #FC4C01“), und jeden vorgelesenen Text kannst du über
labelsüberschreiben.
Wie funktioniert ein Color Picker auf dem Smartphone?
Unter 768px öffnet sich das Panel in einem Bottom Sheet statt in einem Popover: volle Breite, ein höheres Farbfeld, 28px große Griffe und größere Swatches. Änderungen im Sheet sind ein Entwurf, bis jemand auf Fertig tippt, und wer das Sheet wegzieht, behält die alte Farbe. onValueChange feuert dort erst bei Fertig, eine Live-Vorschau an anderer Stelle der Seite folgt dem Ziehen auf Smartphones also nicht. Setz responsive={false}, wenn du das Popover auch auf Smartphones willst. Das Muster und seine Kompromisse beschreibt unser Guide zum React Bottom Sheet fürs Web.
Kannst du das Panel in ein eigenes Popover oder direkt in die Seite einbauen?
Ja. Zwei Optionen decken die meisten Layouts ab:
inlinerendert das Panel direkt an Ort und Stelle, ohne Trigger und ohne Popover, für eine Einstellungsseite, auf der Änderungen sofort gelten.ColorPickerPanelist nur das Panel, mit denselben Propsvalue,format,alpha,swatchesundlabels, für deine eigene Fläche. Hier sitzt es im kostenlosen Popover hinter einem Button in der Toolbar:
Für eine kompakte Toolbar ohne eigenes Popover macht trigger="swatch" aus dem Feld einen runden Button in der Größe eines Icon-Buttons.
Was geht beim Speichern von Picker-Farben schief?
Drei Fehler fallen meist erst nach dem Launch auf, wenn echte Daten gespeichert sind:
- Der Umweg über HSL. Die
hsl()-Ausgabe rundet jeden Kanal auf ganze Zahlen. Aus#FC4C01wirdhsl(18, 99%, 50%), und wieder eingelesen ergibt das#FE4D01. Speichere Hex oder rgb, wenn der genaue Wert zählt, und nutze hsl nur zur Anzeige. - Ein kontrollierter Wert in einem anderen Format. Übergibst du
"rgb(252 76 1)"mitformat="hex", zeigt der Picker den Wert wie übergeben und gibt bei der nächsten Änderung Hex aus. Normalisiere einmal mitparseColorundformatColor, wenn deine Datenbank eine einheitliche Form braucht. - Eine Markenfarbe mit schwachem Kontrast.
colorVarswechselt erst über einer OKLCH-Helligkeit von 0,7 auf schwarzen Text.#FC4C01liegt bei 0,66 und bekommt deshalb weißen Text mit einem Kontrastverhältnis von 3,4:1. Das liegt unter den 4,5:1, die WCAG AA für Fließtext verlangt (Schwarz käme auf 6,2:1). Prüf den Kontrast inonValueCommitvor dem Speichern und zeig das Problem über die Properror, die die Beschreibung ersetzt und das Feld als ungültig markiert.
Wo fängst du an?
Installiere den Picker und verbinde onValueCommit mit der Stelle, an der du das Theme speicherst:
Der Color Picker gehört zu Wingo UI Pro; Popover, Field und Drawer, auf denen er aufbaut, sind kostenlos. Für den Rest des Formulars (Labels, Fehler, Validierung mit zod) lies unseren Guide zu React-Formularkomponenten. Die Kategorie Komponenten-Guides sammelt alle Beiträge dieser Art.
Häufige Fragen
Hat shadcn/ui einen Color Picker?
Nein. Stand Oktober 2026 listet die Komponentenseite von shadcn/ui Popover, Slider und Input, aber keinen Color Picker, und verweist für Community-Komponenten auf das eigene Registry-Verzeichnis. Du baust ihn also aus diesen Teilen zusammen oder installierst eine fertige Komponente aus einer Registry.
Welche Browser unterstützen die EyeDropper API?
Laut caniuse (Stand Oktober 2026) Chrome und Edge ab Version 95 und Opera ab Version 81 auf dem Desktop. Safari, Firefox und Chrome für Android unterstützen sie nicht, also prüfst du window.EyeDropper nach dem Mount und blendest den Button aus, wo die API fehlt.
Kann ein React Color Picker OKLCH ausgeben?
Der Picker von Wingo UI gibt hex, rgb() oder hsl() aus, weil er in sRGB arbeitet, und die Picker von react-colorful decken laut README im Oktober 2026 nur HEX, RGB, HSL und HSV ab. Wandle in CSS mit oklch(from #FC4C01 l c h) um oder in JavaScript mit den OKLab-Formeln von Björn Ottosson, und schreib Tokens mit erweitertem Farbraum (Wide Gamut) von Hand in CSS.
Wie speichere ich die Farbe erst, wenn das Ziehen vorbei ist?
Nutze zwei Callbacks: onValueChange für die Live-Vorschau und onValueCommit zum Speichern. Der Color Picker von Wingo UI ruft onValueCommit in diesen Fällen auf: beim Loslassen, bei Enter oder Blur in einem Feld, bei einem Swatch, einem Pick mit der Pipette, einer Taste im Farbfeld oder beim Fertig-Button im Sheet auf dem Smartphone.
Ist der Color Picker von Wingo UI kostenlos?
Nein, der Color Picker gehört zu Wingo UI Pro. Popover, Field, Drawer, Segmented Control und Button, auf denen er aufbaut, sind kostenlos.
- Komponenten
- React
- Tailwind CSS
- Formulare
- Farbe


