Skip to content

Hex to OKLCH Converter

Convert HEX to OKLCH for Tailwind v4 design tokens. Live perceptually-uniform output with Display P3 gamut warnings. Free, browser-only.

No Tracking Runs in Browser Free
All color conversion happens locally in your browser. No data is sent to any server.
Gamut: sRGB Display P3 Rec2020
Contrast vs:
AA AA-Lg AAA AAA-Lg · APCA Lc
Color blindness simulation (8 types)
Protanopia (red-blind)
Deuteranopia (green-blind)
Tritanopia (blue-blind)
Achromatopsia (total)
Protanomaly (red-weak)
Deuteranomaly (green-weak)
Tritanomaly (blue-weak)
Achromatomaly (partial)
Tints / Shades / Tones / Harmonies

Tints

Shades

Tones

Harmonies

Copy as code
Common colors reference
Reviewed for CSS Color 4 §11.2 + §15.1 conformance, Ottosson 2020 OKLAB matrix correctness, Tailwind v4 palette parity, Display P3 / Rec.2020 gamut detection accuracy, and round-trip stability between HEX and OKLCH across the 0-1 Lightness, 0-0.4 Chroma, and 0-360° Hue ranges. — Go Tools Engineering Team · May 27, 2026

What Is a Hex to OKLCH Converter?

A hex to OKLCH converter is a small utility that turns a hex color code (`#3b82f6`) into the perceptually-uniform Lightness / Chroma / Hue triple that encodes the same color in OKLCH space (`oklch(0.629 0.193 263.4)`). Hex codes are the terse base-16 strings designers and developers paste between Figma, Sketch, Photoshop, brand-guideline PDFs, and CSS stylesheets — three 8-bit channels packed into a 6-character `#RRGGBB` form, anchored to the sRGB color space defined by IEC 61966-2-1 in 1996. OKLCH is the polar form of OKLAB, Björn Ottosson's 2020 perceptually-uniform color space, added to CSS via the `oklch()` syntax in CSS Color 4 (W3C Candidate Recommendation since 2022). Channels are Lightness (0-1, also writable as 0-100%), Chroma (0 to about 0.4 for the most saturated sRGB colors, unbounded above for wide-gamut colors), and Hue (0-360°, the same angular axis HSL uses). Browser support landed across all evergreens between March 2022 (Safari 15.4) and May 2023 (Firefox 113), with Chrome 111 in the middle (March 2023) — combined caniuse coverage is over 94%. Example: Tailwind blue-500 is `oklch(0.629 0.193 263.4)`.

**Perceptual uniformity — why it matters.** In OKLCH (and its rectangular cousin OKLAB), equal numeric distance in the L channel corresponds to equal perceived distance in brightness — across every hue, every chroma level, every region of the color space. In HSL, equal L values look unevenly bright across hues because HSL inherits sRGB's gamma quirks: a green at `hsl(120 100% 50%)` looks visibly brighter than a blue at `hsl(240 100% 50%)`, even though both report L=50%. The structural cause is that HSL derives L geometrically (average of channel max and min in gamma-encoded sRGB), while OKLCH derives L from a perceptually-anchored model that linearizes first and routes through an LMS cone-response stage. The practical upshot: holding L constant across hues in OKLCH produces visually-equivalent brightness — a green at `oklch(0.7 0.2 130)` and a blue at `oklch(0.7 0.2 250)` look equally bright on screen. This is why Tailwind v4 migrated its default palette to OKLCH-based ramps in 2025 — every shade step (50, 100, 200, …, 900, 950) hits the same perceived lightness difference, so brand colors feel consistent across hues without per-color hand-tuning.

**Tailwind v4 and the design-token revolution.** Tailwind v4 (released January 2025) replaced its HSL-based color generation with an OKLCH-based system. shadcn/ui followed shortly after, adopting OKLCH for its CSS-variable theme; Radix Colors v3 also adopted it. Why now: design systems need shades that look evenly-spaced across the entire palette, and they need that property to hold automatically as the palette grows. With HSL, designers had to manually correct each color step — bumping L by 5% extra on the dark end of the blue ramp to match the dark end of the green ramp, then re-bumping when the brand evolved. With OKLCH, a single formula (step L by 0.1, hold C and H constant) produces consistent ramps automatically. Real example: in Tailwind v3, `red-500` and `blue-500` had visibly different perceived weights despite identical HSL L%; in v4, `red-500` and `blue-500` look balanced because both sit at the same OKLCH L. This matters for accessibility (consistent contrast against shared backgrounds means component states feel uniform across the palette), brand consistency (visual hierarchy holds across palettes — a `primary` button and an `accent` button at the same L feel like the same hierarchy level), and developer ergonomics (one mental model instead of dozens of hand-tuned exceptions buried in the design-token spec).

**Wide-gamut implications.** OKLCH is unbounded — it can represent colors outside sRGB, including everything Display P3 and Rec.2020 can reproduce. This makes it the natural choice for modern wide-gamut displays. Most Apple devices since 2017 (iPhone 7 onward, MacBook Pro 2016 onward, every iPad Pro) render Display P3 natively, and many modern Android devices and laptop screens do too. The tradeoff: not every OKLCH triple maps to a valid sRGB color. The tool shows three gamut badges — sRGB, Display P3, Rec.2020 — so you can see immediately whether the current OKLCH will display correctly on a given target. When the color is sRGB-only, the **Snap to sRGB** button uses binary chroma reduction (per CSS Color 4 §13's informative gamut-mapping algorithm) to shrink the color into gamut while preserving L and H — giving you a hex fallback you can ship via `@supports not (color: oklch(0 0 0))` alongside the original OKLCH value for the wider-gamut clients.

**The HEX → OKLCH conversion math.** The pipeline is well-defined and grounded in two primary sources: W3C CSS Color 4 for the sRGB and XYZ stages, Ottosson 2020 for the OKLAB stage. Step one: parse `#RRGGBB` to three 8-bit integer sRGB channels via `parseInt(hex.slice(1, 3), 16)` per channel. Step two: normalize each channel to 0-1 by dividing by 255. Step three: gamma-decode to linear-sRGB via the CSS Color 4 §11.2 piecewise function (`v <= 0.04045 ? v/12.92 : ((v+0.055)/1.055)^2.4`). Step four: multiply by the §15.1 3×3 matrix to get CIE XYZ D65 coordinates. Step five: multiply by Ottosson's LMS matrix (from his 2020 reference implementation) and take the cube root of each channel. Step six: multiply by Ottosson's OKLAB matrix to get L / a / b. Step seven: Cartesian-to-polar — `C = sqrt(a² + b²); H = atan2(b, a) * 180 / π`, wrap H into 0-360°. The full pipeline runs in microseconds — every keystroke re-renders the OKLCH output instantly with no debounce.

This tool's HEX → OKLCH workflow is one direction of a 5-spoke family that all share the same underlying unified color converter. The dedicated unified color converter is the hub — it shows all 9 formats simultaneously editable and is the right tool when your workflow needs more than just hex and OKLCH. The single-direction spokes target specific Google search intents: the hex to RGB converter for the canvas-and-hardware direction, the RGB to hex converter for the inverse, the hex to HSL converter for the legacy designer-cylindrical space still used in many Tailwind v3 codebases, and the hex to CMYK converter for print-prep approximations. All five spokes and the hub share the same OKLCH source-of-truth internally and the same Ottosson 2020 matrices, so the results are guaranteed identical across the family. Every conversion runs locally in your browser — your hex codes are never uploaded, never logged, and zero network requests fire as you type. Verify in DevTools. For a deeper dive into why OKLCH became the design-system standard in 2024–2026, read our companion guide: OKLCH color space explained — why Tailwind v4 adopted it.

// sRGB hex → OKLCH per W3C CSS Color 4 + Ottosson 2020
// References: https://www.w3.org/TR/css-color-4/#color-conversion-code
//             https://bottosson.github.io/posts/oklab/
// Worked example: #3b82f6 (Tailwind blue-500) → oklch(0.629 0.193 263.4)
function hexToOklch(hex) {
  const h = hex.trim().replace(/^#/, '');
  const srgb = [0, 2, 4].map(i => parseInt(h.slice(i, i + 2), 16) / 255);
  // sRGB → linear-sRGB (CSS Color 4 §11.2 piecewise gamma)
  const lin = srgb.map(v => v <= 0.04045 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4));
  const [lr, lg, lb] = lin;
  // linear-sRGB → XYZ D65 (CSS Color 4 §15.1 matrix)
  const x = 0.4124564 * lr + 0.3575761 * lg + 0.1804375 * lb;
  const y = 0.2126729 * lr + 0.7151522 * lg + 0.0721750 * lb;
  const z = 0.0193339 * lr + 0.1191920 * lg + 0.9503041 * lb;
  // XYZ D65 → LMS (Ottosson 2020), cube-root, → OKLAB
  const l_ = Math.cbrt(0.8189330101 * x + 0.3618667424 * y - 0.1288597137 * z);
  const m_ = Math.cbrt(0.0329845436 * x + 0.9293118715 * y + 0.0361456387 * z);
  const s_ = Math.cbrt(0.0482003018 * x + 0.2643662691 * y + 0.6338517070 * z);
  const L = 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_;
  const a = 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_;
  const b = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_;
  // OKLAB → OKLCH (Cartesian to polar)
  const C = Math.sqrt(a * a + b * b);
  const H = (Math.atan2(b, a) * 180 / Math.PI + 360) % 360;
  return `oklch(${L.toFixed(3)} ${C.toFixed(3)} ${H.toFixed(1)})`;
}
console.log(hexToOklch('#3b82f6')); // → oklch(0.629 0.193 263.4)

Key Features

Perceptually-Uniform Output Across All Hues

OKLCH's L channel is anchored to the OKLAB perceptual model (Ottosson 2020), so every L step looks like the same brightness change across all hues — a green at `oklch(0.7 0.2 130)` and a blue at `oklch(0.7 0.2 250)` read as equally bright on screen. This is the structural property that lets Tailwind v4 generate visually-even ramps automatically without per-color hand-tuning, the same property the equivalent HSL ramp can't guarantee because HSL inherits sRGB's gamma quirks.

Tailwind v4 Ready — Drop Into @theme Blocks

The OKLCH output uses CSS Color 4's space-separated form (`oklch(0.629 0.193 263.4)`) — the exact syntax Tailwind v4 expects inside an `@theme` block as `--color-primary: oklch(0.629 0.193 263.4);`. The L precision matches Tailwind's published palette precision (three decimals on L and C, one decimal degree on H), so a paste-into-config workflow produces identical tokens to those Tailwind ships by default. Pair with the Copy as code section's Tailwind v4 snippet for the full token line.

Display P3 + Rec.2020 Gamut Badges

Three live badges (sRGB, Display P3, Rec.2020) flag whether the current OKLCH triple falls inside each space's reproducible range. Useful because OKLCH is unbounded — many high-chroma colors exceed sRGB but fit P3, which most Apple devices since 2017 can render natively. The badges turn red on out-of-gamut so you can decide whether to keep the wider-gamut value for modern displays or snap to sRGB for universal compatibility. Channel-range check runs on every keystroke.

Snap to sRGB for Legacy Compatibility

The Snap to sRGB button runs binary chroma reduction (CSS Color 4 §13 informative algorithm): hold L and H fixed, search C downward until the resulting sRGB conversion stays in-gamut. The search terminates in ~30 iterations at sub-pixel precision. Preserving L and H means the snapped color reads as the same hue family at the same brightness — it just loses saturation, which is the least visually-jarring compromise. The snapped hex pairs with the original OKLCH via `@supports not (color: oklch(0 0 0))` for layered fallback.

Per-Keystroke Instant Conversion

There is no Convert button. Type a single character into the HEX field and the OKLCH field updates in the same animation frame. The internal canonical representation is the OKLCH triple itself, so editing OKLCH directly is equally fast — the cursor stays where you put it, only the other format fields re-render. The conversion math (sRGB → linear → XYZ → LMS → OKLAB → polar) runs in microseconds; no debounce, no latency, no visible reflow.

Worked Example via W3C + Ottosson 2020 Pipeline

The code-example section ships a working JavaScript implementation of the full HEX → OKLCH pipeline using the exact matrices and gamma function published in W3C CSS Color 4 (§11.2 piecewise gamma, §15.1 linear-sRGB → XYZ D65 matrix) and Björn Ottosson's 2020 OKLAB reference implementation. Paste into a Node REPL and verify `#3b82f6` yields `oklch(0.629 0.193 263.4)`. Every matrix value is copy-pasted from its primary source — no re-derivations or rounding.

Bidirectional With HSL / RGB / HEX in the Unified Hub

Although this spoke targets HEX → OKLCH specifically, the same page exposes the other eight format fields too — RGB for hardware, HSL for legacy CSS, OKLAB for palette math, HSV/HWB for picker UIs, CMYK for print, and the closest CSS named color. The internal OKLCH source-of-truth means every field is bit-stable across round-trips: HEX → OKLCH → HSL → HEX recovers the original hex. Click into any field to edit it directly and watch the others update.

Browser Support Summary Inline

The tool surfaces the canonical browser-support data points where relevant: Chrome and Edge 111 (March 2023), Safari 15.4 (March 2022 — the earliest), Firefox 113 (May 2023), combined caniuse coverage over 94%. For older clients, wrap tokens in `@supports (color: oklch(0 0 0))` and provide a hex fallback in the alternate branch. The Snap to sRGB output is exactly that fallback, generated automatically from the current OKLCH triple — no manual chroma-tuning needed.

100% In-Browser — No Upload, No Tracking

All hex parsing, OKLCH conversion, gamut detection, contrast scoring, and palette generation runs locally in your browser. Your hex codes are never transmitted, never logged on any server, never analyzed. Zero network requests as you type — verify in DevTools. Safe for unannounced brand palettes, internal design tokens for unreleased products, draft mockups under NDA, and any other confidential color work where the value can't leak.

Hex to OKLCH Converter Alternatives

OKLCH.com

browser tool

Beautifully-built OKLCH-focused tool by Andrey Sitnik (author of the postcss-oklab-function polyfill and Autoprefixer). Best-in-class for pure OKLCH exploration with a wide-gamut-aware picker, P3-aware visualization, and palette generation. Doesn't cover HEX/RGB/HSL/CMYK conversion as primary outputs — focused on OKLCH alone. Reach for OKLCH.com when you're doing deep OKLCH design work; reach for this tool when you also need cross-space conversion and the gamut/contrast/CVD features.

Tailwind v4 Documentation Palette

documentation reference

The Tailwind v4 docs publish the full default palette in OKLCH alongside the hex equivalents. Best for looking up an exact Tailwind shade (`blue-500` → `oklch(0.629 0.193 263.4)`) or matching custom colors to the visual weight of a Tailwind shade. Not interactive — no conversion of arbitrary hex codes. This tool covers the same OKLCH precision and works for any hex, not just the 200+ Tailwind defaults.

ColorJS.io Playground

browser tool

ColorJS.io is Lea Verou and Chris Lilley's authoritative CSS color library; the playground exposes the full conversion graph (HEX, RGB, HSL, HWB, LCH, OKLCH, OKLAB, P3, Rec2020, ProPhoto, A98). Deeply correct math, ideal for spec-level color work. UI is developer-focused (not designer-focused) and lacks the contrast / CVD / palette features. Pair with this tool: use ColorJS.io for the math you can't otherwise verify, use this tool for active workflows.

shadcn/ui Themes Generator

browser tool

Vercel's shadcn theme generator produces ready-to-paste OKLCH CSS-variable themes for shadcn/ui projects. Best for end-to-end theme generation when the deliverable is a shadcn config file. Doesn't surface intermediate OKLCH values for arbitrary hex codes — focused on the full theme workflow. Use the shadcn generator when you're building a shadcn theme; use this tool when you need the OKLCH of any individual color.

ColorHexa

browser tool

Long-running per-color SEO pages with deep metadata. Recently added OKLCH support alongside HEX/RGB/HSL/CMYK. UI is dated (early-2010s), no wide-gamut detection, no APCA contrast. Strong for SEO discovery of a specific hex via Google; weaker for active conversion workflows where the unified-field UX and gamut/contrast features matter. This tool wins on every active-workflow axis.

Browser DevTools Color Picker

built-in browser feature

Chrome, Firefox, and Safari DevTools all ship a color picker that toggles between HEX, RGB, HSL, HWB, and OKLCH inline when you click a color swatch in the CSS pane. Free, no install, always available. Lacks the gamut badges, contrast scoring, color-blindness simulation, and code-export for non-web platforms (SwiftUI, Compose). Reach for DevTools when you're already debugging CSS; reach for this tool when you need cross-platform output or the deeper checks.

Culori CLI

command-line library

Culori is the most thorough OKLCH-aware JavaScript color library; its CLI handles HEX → OKLCH conversion as a one-liner (`culori convert '#3b82f6' --to oklch`). Excellent for CI scripts and batch token migration. No visual picker or gamut badges. Use Culori CLI for automation; use this tool for interactive single-color work and the immediate visual feedback.

Hex to OKLCH Examples

Migrate Tailwind 3 HSL palette → v4 OKLCH tokens

#3b82f6

OKLCH output: `oklch(0.629 0.193 263.4)`. The canonical Tailwind v4 migration workflow: define the brand color once in your `@theme` block as `--color-primary: oklch(0.629 0.193 263.4)`, then compose tints by stepping L upward (`oklch(0.7 0.193 263.4)`, `oklch(0.8 0.15 263.4)`) and shades by stepping L downward (`oklch(0.5 0.193 263.4)`, `oklch(0.4 0.18 263.4)`). Hue stays locked at 263.4°, chroma anchors near 0.19, lightness is the only axis sweeping — a one-dimensional ramp that reads as visually-even across the entire scale, which the equivalent HSL ramp can't guarantee.

Design-token migration with perceptually-uniform shades

#FF5733

OKLCH output: roughly `oklch(0.66 0.18 28)`. To build a 5-step shade ramp from this brand orange, hold C = 0.18 and H = 28 constant and step L through 0.3, 0.45, 0.6, 0.75, 0.9 — producing `oklch(0.3 0.18 28)` through `oklch(0.9 0.18 28)`. Each adjacent pair feels like the same visual jump in brightness, because OKLCH's L is anchored to the OKLAB perceptual model (Ottosson 2020) rather than HSL's gamma-tangled geometric L. The chroma may quietly clip toward sRGB at the extremes; the tool's gamut badges flag exactly which steps need attention.

Wide-gamut OKLCH → sRGB fallback for Tailwind v3 sites

#FF1744

OKLCH output: approximately `oklch(0.62 0.27 26)`. A high-chroma red like this exceeds the sRGB cube — the **sRGB** gamut badge lights up red, the **Display P3** badge confirms it fits P3, and Rec.2020 covers it too. On a standard 24-bit monitor it renders as a desaturated approximation; on a Display P3 screen (most Apple devices since 2017) it renders saturated. Click **Snap to sRGB** to run the binary chroma-reduction algorithm (CSS Color 4 §13 informative) — L and H stay locked while C shrinks until the color fits, producing a hex fallback suitable for a Tailwind v3 codebase that still uses 8-bit hex tokens.

shadcn/ui theme migration

#0f172a

OKLCH output: approximately `oklch(0.21 0.04 264.7)`. shadcn/ui migrated its CSS-variable theme to OKLCH shortly after Tailwind v4 landed, and `#0f172a` (Tailwind slate-900) is the canonical dark-mode background. The tool reproduces shadcn's published OKLCH value for the same hex, so you can verify a community theme port matches the upstream definition. Pair with the contrast row to confirm the dark-mode foreground (white or near-white) still clears WCAG AA against this background — `oklch(0.21 ...)` against `oklch(1 0 0)` reports a comfortable 16:1 ratio.

Build a Tailwind v4 dark/light pair from a brand hex

#3b82f6

OKLCH output: `oklch(0.629 0.193 263.4)`. To derive a matched dark/light pair for a theme, pivot only the L channel while holding C and H constant: the light-mode primary becomes `oklch(0.7 0.15 263)` (slightly brighter, slightly less chromatic to avoid eye strain on white backgrounds), the dark-mode primary becomes `oklch(0.5 0.18 263)` (slightly darker, slightly more chromatic to retain saliency on dark backgrounds). Both variants read as the same brand identity because hue is locked; the perceptual L shift balances readability across both modes without manual per-channel RGB tuning.

Common Hex → OKLCH Conversions (Tailwind v4)

Reference table of 10 popular Tailwind v4 default-palette mid-shades with their HEX and OKLCH equivalents. Values match Tailwind v4's published palette precision (three decimals on L and C, integer or one-decimal on H).

Tailwind slate-500

#64748b oklch(0.55 0.04 257)

Tailwind CSS's default slate-500 — the neutral cool gray used for body text, secondary surfaces, and de-emphasized UI elements. Low chroma (0.04) keeps it visually neutral.

#64748b oklch(0.55 0.04 257)

slate is the canonical neutral ramp for dark-mode-friendly themes — every slate shade sits at very low chroma so they read as gray rather than blue-tinged.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind gray-500

#6b7280 oklch(0.55 0.03 258)

Tailwind CSS's default gray-500 — the true-neutral counterpart to slate. Slightly lower chroma than slate (0.03 vs 0.04) for a more achromatic appearance.

#6b7280 oklch(0.55 0.03 258)

gray and slate sit at almost identical L (0.55) — the perceptual brightness is matched, only the tiny chroma difference distinguishes them.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind red-500

#ef4444 oklch(0.64 0.21 25)

Tailwind CSS's default red-500 — the canonical destructive-action / error red. High chroma (0.21) keeps it salient against neutral backgrounds.

#ef4444 oklch(0.64 0.21 25)

red-500 sits at L=0.64, matching blue-500's L=0.63 — the v4 ramps are perceptually-balanced across hues, unlike v3's HSL-based palette.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind orange-500

#f97316 oklch(0.71 0.19 42)

Tailwind CSS's default orange-500 — the warm-accent and CTA hue. Sits between red and amber on the hue circle (42°).

#f97316 oklch(0.71 0.19 42)

orange-500's higher L (0.71) vs red-500's L (0.64) is intentional — yellows and oranges look bright at lower perceptual L than reds.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind amber-500

#f59e0b oklch(0.76 0.16 70)

Tailwind CSS's default amber-500 — the warning / caution hue, between orange and yellow on the wheel.

#f59e0b oklch(0.76 0.16 70)

amber-500 hits the highest L (0.76) of any 500-level Tailwind color — yellows naturally need higher L to appear visually as 'mid-tone'.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind green-500

#22c55e oklch(0.72 0.19 149)

Tailwind CSS's default green-500 — the success / confirmation hue. Sits at 149° on the hue wheel, in the cyan-green region.

#22c55e oklch(0.72 0.19 149)

green-500 at L=0.72 is a touch brighter than red-500 at L=0.64 — this matches perceptual reality (greens look bright) and gives the palette balanced visual weight.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind teal-500

#14b8a6 oklch(0.7 0.13 184)

Tailwind CSS's default teal-500 — the cool-accent hue between green and cyan. Lower chroma than green-500 because high-chroma teals push past sRGB easily.

#14b8a6 oklch(0.7 0.13 184)

teal-500's H=184° sits just past cyan (180°) — pure cyan in OKLCH is hard to express in sRGB without chroma clipping; teal is the practical compromise.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind blue-500

#3b82f6 oklch(0.63 0.19 263)

Tailwind CSS's default blue-500 — the canonical 'web blue' of the 2020s, the brand-anchor color for the v4 palette and shadcn/ui's default theme.

#3b82f6 oklch(0.63 0.19 263)

blue-500 is the reference color most often used as a Tailwind v4 OKLCH migration starting point — paste #3b82f6 here to verify the conversion against the published value.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind indigo-500

#6366f1 oklch(0.59 0.21 277)

Tailwind CSS's default indigo-500 — the cool-accent companion to blue, sitting at 277° (toward purple). High chroma (0.21) gives it saliency.

#6366f1 oklch(0.59 0.21 277)

indigo-500 sits at lower L than blue-500 (0.59 vs 0.63) — the deeper hue absorbs more apparent brightness, and the v4 ramp accounts for it perceptually.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

Tailwind violet-500

#8b5cf6 oklch(0.6 0.24 295)

Tailwind CSS's default violet-500 — the purple-accent hue at 295°. Highest chroma (0.24) of any Tailwind 500-level color, often used for AI / creative-product branding.

#8b5cf6 oklch(0.6 0.24 295)

violet-500's high C=0.24 puts it close to the sRGB gamut ceiling — push much higher and it crosses into P3-only wide-gamut territory.

Need the full color picker with RGB, HSL, CMYK, gamut warnings, and code export? Try the unified color converter — every format simultaneously editable.

How to Use the Hex to OKLCH Converter

  1. 1

    Paste a hex code into the HEX field

    Drop any hex value into the HEX input — with or without the leading `#`, in 3-digit shorthand (`#F73`), 6-digit full form (`#3b82f6`), 4-digit alpha shorthand (`#F738`), or 8-digit alpha full form (`#FF573380`). The parser normalizes all five input shapes into the same internal color before deriving OKLCH. Capitalization doesn't matter (`#3b82f6` and `#3B82F6` parse identically). Invalid characters or wrong digit counts produce a quiet inline error; valid hex updates every other format field in real time, including OKLCH.

  2. 2

    Read the OKLCH triple from the OKLCH field

    The OKLCH field surfaces the value in CSS Color 4's modern form: `oklch(0.629 0.193 263.4)` for an opaque color, `oklch(0.629 0.193 263.4 / 0.5)` for an alpha-bearing one. L is rounded to three decimals (matches Tailwind v4's published precision), C to three decimals, H to one decimal degree. The tool's internal OKLCH source-of-truth means the underlying float precision is preserved across every other field — round-trips back to hex stay bit-stable, unlike legacy HSL-pivot converters that drift by a degree or two per round-trip.

  3. 3

    Click Copy to grab the OKLCH string

    Each format card has a Copy button on the right. One click and the value lands on your clipboard — the button label briefly flashes "Copied!" so you know. The copied string is the canonical CSS Color 4 syntax (`oklch(0.629 0.193 263.4)`), ready to drop into a Tailwind v4 `@theme` block or a shadcn/ui CSS-variable definition. For platform-specific output (CSS custom property, Tailwind v4 token, SwiftUI, Compose, Flutter), use the Copy as code section below the picker — those snippets emit the format each platform expects natively.

  4. 4

    Check the Display P3 / Rec.2020 gamut badges

    Three gamut badges (sRGB, Display P3, Rec.2020) show whether the current color falls inside each space's reproducible range. If the sRGB badge turns red but P3 is green, the color is a wide-gamut OKLCH that will render saturated on Apple hardware (iPhone, iPad, MacBook from 2017+) but desaturate on a legacy 24-bit monitor. The **Snap to sRGB** button uses binary chroma reduction (CSS Color 4 §13 informative algorithm) to shrink the color into sRGB while preserving L and H, producing a hex fallback you can ship via `@supports not (color: oklch(0 0 0))`.

  5. 5

    Also visible: RGB, HSL, OKLAB, HSV, HWB, CMYK, named color

    The same hex you paste lights up the other eight format fields too — RGB for canvas calls and hardware, HSL for legacy CSS variables, OKLAB for palette math and color-blindness matrices, HSV and HWB for designer color-picker workflows, CMYK for print estimates, and the closest CSS named color for documentation prose. You're never locked into hex → OKLCH only. The picker (SL square + hue slider + alpha slider) drives all nine simultaneously, and on Chromium browsers the EyeDropper button samples any pixel on screen, including outside the browser.

Common Hex / OKLCH Mistakes

Reading OKLCH Chroma Like HSL Saturation

OKLCH Chroma is unbounded (0 to ~0.4 for sRGB-fitting colors, higher for wide-gamut) — it is NOT a 0-100% saturation percentage like HSL's S. Assuming C=0.3 means "30% saturated" misreads the scale: 0.3 is highly chromatic, near the sRGB ceiling for some hues and well past it for others. The maximum C varies by L and H — a green at L=0.7 supports much higher C than a blue at L=0.3. Treat C as an absolute distance from gray, not a relative percentage.

✗ Wrong
Set OKLCH C = 0.3 expecting "30% saturation":
oklch(0.7 0.3 250) → may exceed sRGB gamut for blues
Wide-gamut color renders desaturated on legacy displays.
✓ Correct
Treat C as absolute chroma, check gamut badges:
oklch(0.7 0.15 250) → comfortably in sRGB for this L+H pair
Use the badges to find the max C that fits the target gamut.

Treating OKLCH L the Same as HSL L

Both spaces report Lightness as a 0-1 (or 0-100%) axis, but they measure different things. HSL L is geometric — derived from RGB max/min averaging in gamma-encoded sRGB. OKLCH L is perceptual — anchored to the OKLAB model. Porting an HSL-based palette as `oklch(L%, C, H)` and expecting matched brightness produces uneven results because the L relationship between the two spaces is non-linear. For mid-tone colors OKLCH L = 0.6 is roughly HSL L = 50%, but the curve drifts at the dark and light ends.

✗ Wrong
Copy HSL L percentages into OKLCH directly:
hsl(220 50% 30%) ported as oklch(0.30 0.10 220)
The two colors look noticeably different in brightness.
✓ Correct
Re-derive OKLCH from the original hex, don't port HSL:
hex source → OKLCH conversion → oklch(0.34 0.08 254)
The perceptual L stays correct; the palette feels even.

Forgetting Wide-Gamut OKLCH Won't Display in sRGB

OKLCH is unbounded — you can write `oklch(0.7 0.4 30)` and the syntax is valid, but the chroma exceeds what sRGB's 256-per-channel byte space can encode. On an sRGB monitor that color clips to the nearest in-gamut approximation (usually a desaturated version). On a Display P3 monitor it renders correctly. Shipping a wide-gamut OKLCH without checking the gamut badges produces a color that looks different on different displays — a subtle but real cross-platform consistency bug.

✗ Wrong
Ship oklch(0.7 0.4 30) without checking sRGB gamut:
P3 displays render saturated red; sRGB displays render desaturated
Brand color looks inconsistent across user hardware.
✓ Correct
Check sRGB gamut badge, Snap to sRGB if needed, layer with @supports:
@supports (color: oklch(0 0 0)) { --primary: oklch(0.7 0.4 30); }
@supports not (color: oklch(0 0 0)) { --primary: #ef6b50; }
P3 hardware gets the wide-gamut value; sRGB hardware gets the snapped fallback.

Missing Browser Support for oklch()

Native `oklch()` parsing landed in Chrome and Edge 111 (March 2023), Safari 15.4 (March 2022), and Firefox 113 (May 2023). Combined caniuse coverage is 94%+, but the remaining 6% includes IE 11, old Safari on iOS 15.3 or earlier, old Android Chrome, and embedded webviews. Shipping `oklch()` without a fallback to that long tail renders as the CSS `inherit` value or fails entirely. Always feature-detect with `@supports` for production sites with broad audiences.

✗ Wrong
Define brand color in OKLCH only:
:root { --primary: oklch(0.629 0.193 263.4); }
IE 11 and old iOS Safari render no color at all.
✓ Correct
Layer with @supports for graceful fallback:
:root { --primary: #3b82f6; }
@supports (color: oklch(0 0 0)) { :root { --primary: oklch(0.629 0.193 263.4); } }
Modern browsers get OKLCH; legacy browsers get the hex fallback.

Confusing OKLCH and LCH (CIE-LAB Polar Form)

CSS Color 4 ships both `oklch()` and `lch()`. They look identical in shape (L / C / H) but use different underlying spaces: `lch()` is the polar form of CIE-LAB (1976), `oklch()` is the polar form of OKLAB (Ottosson 2020). The two are NOT interchangeable — `lch(60% 50 240)` and `oklch(0.6 0.15 240)` describe different colors. CIE-LAB's perceptual uniformity breaks down around saturated blues, which is why Ottosson re-derived OKLAB. For new design-system work, prefer `oklch()` over `lch()`.

✗ Wrong
Substitute lch() for oklch() expecting same result:
lch(60% 50 240) ≠ oklch(0.6 0.15 240) — different colors entirely
Copy-pasted across spaces, the value is silently wrong.
✓ Correct
Pick one space and stay in it:
oklch(0.629 0.193 263.4) for modern design systems
or lch(60% 50 240) — but don't swap function names without re-converting

Who Uses Hex to OKLCH

Frontend Devs Migrating to Tailwind v4 OKLCH Tokens
Tailwind v4 standardized on OKLCH for its default palette in January 2025. Migrating a v3 codebase with hex-based brand colors means converting each hex to OKLCH and dropping the result into the new `@theme` block. Paste each hex here, copy the `oklch()` value, define `--color-primary: oklch(0.629 0.193 263.4)` and friends. The live gamut badges flag any colors that exceed sRGB so you can decide whether to keep the wide-gamut value for Display P3 users or snap to sRGB.
shadcn/ui Theme Authors Building Custom Palettes
shadcn/ui's CSS-variable theme uses OKLCH for every token (`--background`, `--foreground`, `--primary`, etc.). Custom themes derive from a base brand hex by converting to OKLCH and then sweeping L for the light/dark variants. Paste the brand hex, read the OKLCH triple, build out the rest of the theme by stepping L while holding C and H fixed. Matches the canonical shadcn workflow exactly.
Design-System Authors Generating Perceptually-Even Ramps
Generate a 50/100/200/.../900 ramp by stepping the L channel in equal OKLCH increments while holding C and H fixed. The visual gap between adjacent stops looks identical across every hue — what a brand-color palette actually needs. Tailwind v4 uses exactly this construction for its default palette, and shadcn/ui mirrors it. Paste each brand hex, read the OKLCH, generate the ramp algorithmically or via the Tints/Shades/Tones panel below the picker.
Accessibility Engineers Verifying Contrast in OKLCH Space
WCAG 2.1 and APCA contrast both report against the resolved sRGB color, not the OKLCH triple — but knowing the OKLCH L of a brand color makes contrast tuning predictable: bump L by 0.1 to clear AA against white, drop L by 0.1 to clear AA against black. The simultaneous OKLCH + WCAG + APCA view makes the relationship visible. Paste the brand hex, watch the contrast badges, adjust L in OKLCH (more predictable than HSL) until the pair passes both metrics.
Web Devs Building Wide-Gamut Color Tokens for Modern Displays
Most Apple devices since 2017 (and many modern Android devices) render Display P3 natively. Defining brand accent colors in OKLCH lets you address P3-only saturated reds and greens that no hex code can encode. Paste an existing hex to read its OKLCH, then push the C channel above the sRGB ceiling to claim the extra P3 saturation. The gamut badges confirm the new value fits P3 (and falls back gracefully on sRGB-only screens via browser chroma compression).
Educators Teaching Perceptual-vs-Geometric Lightness
The simultaneous OKLCH + HSL view makes the difference between perceptual and geometric lightness obvious. Paste a saturated green and a saturated blue at the same HSL L=50%; the OKLCH L values differ noticeably because OKLCH measures actual perceived brightness. Drag the HSL hue slider and watch OKLCH L wobble while you hold HSL L constant — the curve is the gamma quirk visualized. A classroom-ready demonstration of why design systems migrated to OKLCH.
Open-Source Maintainers Modernizing Token Documentation
Older design-system docs typically list brand colors as hex codes only. Modernizing to OKLCH means showing the same color in both spaces — the hex for code-block compatibility, the OKLCH for the spec table and the modern token definition. Paste each hex, copy the OKLCH output, update the docs. The shareable URL hash also lets contributors link to the exact color under discussion in a GitHub issue without ambiguity.

Hex to OKLCH Math & Pipeline

HEX → OKLCH Is a 7-Step Pipeline
The conversion routes through five intermediate representations: hex → integer sRGB → normalized sRGB (0-1) → linear-sRGB (gamma-decoded) → CIE XYZ D65 → OKLAB → OKLCH. Each step is a well-defined matrix or piecewise function from a primary source. The tool runs the full pipeline on every keystroke; the math is fast enough (microseconds) that no debouncing is needed. Surfacing the intermediate RGB tuple alongside OKLCH means you can debug an unexpected OKLCH value by inspecting the RGB channels.
CSS Color 4 §11.2 Gamma Function
The sRGB → linear-sRGB conversion uses the CSS Color 4 §11.2 piecewise function: `v ≤ 0.04045 ? v/12.92 : ((v + 0.055) / 1.055)^2.4`. The piecewise form (with a small linear segment near zero) avoids the numerical instability of the pure-exponent form at very dark colors. This is the same function ICC profiles use to encode sRGB and the same function browsers use internally when rendering hex codes. The inverse for OKLCH → hex applies the same function in reverse: `v ≤ 0.0031308 ? v * 12.92 : 1.055 * v^(1/2.4) - 0.055`.
CSS Color 4 §15.1 Matrix: linear-sRGB ↔ XYZ D65
The matrix from CSS Color 4 §15.1 converts linear-sRGB to CIE XYZ under the D65 white point: `X = 0.4124564 R + 0.3575761 G + 0.1804375 B`, `Y = 0.2126729 R + 0.7151522 G + 0.0721750 B`, `Z = 0.0193339 R + 0.1191920 G + 0.9503041 B`. The Y row gives the sRGB luminance formula. The matrix is the same one used in every color-management library, including ICC, Adobe Color Engine, and the LCMS open-source pipeline. Inverse matrix for OKLCH → hex applies the §15.1 inverse.
Ottosson 2020 OKLAB Matrices and Cube-Root Step
The XYZ D65 → OKLAB conversion uses two matrices and a cube-root step published in Björn Ottosson's 2020 OKLAB paper. First matrix transforms XYZ to an LMS cone-response space (loosely modeled on human L/M/S cone sensitivities). Cube-root each channel to compress the dynamic range non-linearly (the perceptual-uniformity-correcting step). Second matrix transforms cube-rooted LMS to OKLAB's L/a/b coordinates. All three operations use the exact values published in the paper's reference implementation; no re-derivations or rounding. The inverse for OKLCH → hex applies these matrices in reverse.
OKLAB ↔ OKLCH Is Cartesian-to-Polar
OKLAB's `a` and `b` axes form a chroma plane perpendicular to the L axis. OKLCH polar-encodes that plane: `C = sqrt(a² + b²)` (Euclidean distance from gray), `H = atan2(b, a) * 180 / π` (angle in degrees, wrapped to 0-360°). The inverse: `a = C * cos(H * π / 180)`, `b = C * sin(H * π / 180)`. The polar form is preferred over OKLAB for design-token storage because Hue is a stable axis — rotating Hue doesn't accidentally cross-fade through gray the way rotating `a` or `b` can in OKLAB.
Gamut Detection via Channel-Range Check
A color is considered in-gamut for a target space (sRGB, Display P3, Rec.2020) if every channel falls inside `[-ε, 1 + ε]` after conversion to that space's primaries, where `ε = 1e-7` to absorb float-precision noise around boundaries. The gamut badge for each space turns red when any channel exceeds the range. OKLCH is gamut-unbounded — `oklch(0.7 0.4 30)` is a valid coordinate but may exceed sRGB's 256-per-channel byte space. The check runs on every keystroke; combined with Snap to sRGB, this catches the most common adoption pitfall (wide-gamut OKLCH not displaying correctly on legacy screens).
Snap-to-sRGB Binary Chroma Reduction
Snap to sRGB matches the informative gamut-mapping algorithm in CSS Color 4 §13: hold L and H fixed at the current values, binary-search C ∈ [0, currentC] for the largest C whose sRGB conversion stays in-gamut. The search runs at most 30 iterations (precision ~10⁻⁹), which is more than enough for visual accuracy. Preserving L and H means the snapped color reads as the same hue family at the same brightness — it just loses saturation. We don't clip RGB channels directly because that distorts hue noticeably (especially in blues, which clip toward purple).

Best Practices for Hex / OKLCH Workflows

Use OKLCH as the Canonical Token Format in New Code
For any design system shipping in 2025 or later, define brand colors and palette ramps in OKLCH. The L axis gives perceptually-even ramps automatically; the Chroma axis can address wide-gamut colors that hex can't encode. Keep a hex fallback for older browsers via `@supports not (color: oklch(0 0 0))` or build-time PostCSS, but make OKLCH the source-of-truth in your token store. Tailwind v4 and shadcn/ui both ship this way; new projects can follow their lead with no friction.
Generate Ramps by Stepping L, Holding C and H Constant
The canonical OKLCH ramp construction: lock C and H, sweep L in equal increments. A 9-step ramp `oklch(L 0.15 263)` for L = 0.1, 0.2, …, 0.9 produces visually-even spacing across every step. This is exactly what Tailwind v4 does internally. Don't sweep C alongside L unless you want the ramp's chromatic intensity to vary deliberately (rare). Don't drift H across steps — even a 5° drift makes the ramp feel jumbled.
Match Tailwind v4's Precision: 3 Decimals L+C, 1 Decimal H
Tailwind v4's default palette publishes OKLCH values with three decimal places on L and C, and one decimal place on H — `oklch(0.629 0.193 263.4)` for blue-500. Matching this precision in your own tokens means paste-into-config workflows produce identical values to those Tailwind ships, and diff tools won't flag spurious differences. The tool's default rounding follows this convention; copy-paste into a `@theme` block is bit-exact.
Run Wide-Gamut OKLCH Through the Display P3 Gamut Check
If you're targeting modern Apple hardware (iPhone, iPad, MacBook from 2017+) or shipping HDR-aware content, the gamut badges let you push C above the sRGB ceiling to claim the extra P3 saturation. Browser-applied chroma compression keeps the color from clipping on sRGB-only screens. Don't pre-snap to sRGB by default unless you know your entire audience is on legacy displays — that loses 30%+ of the saturation P3 hardware can render.
Provide a Hex Fallback via @supports for Pre-2023 Browsers
Although evergreen browser support for `oklch()` is now 94%+, the long tail (IE 11, old Android Chrome, embedded webviews) still needs a fallback. Wrap tokens in `@supports (color: oklch(0 0 0))` and provide a hex variant in the alternate branch. The Snap to sRGB output is exactly that fallback — generated automatically from the current OKLCH triple with L and H preserved. Build-time PostCSS plugins like `postcss-oklab-function` can also inline the sRGB approximation at compile time.
Document Both the OKLCH and the Source Hex in Your Tokens
When you ship a CSS variable like `--color-primary: oklch(0.629 0.193 263.4)`, include a comment with the source hex: `/* source: #3b82f6 (Tailwind blue-500) */`. Six months later, when someone needs to derive a related shade or check the value against a brand-guidelines PDF, the source hex preserves the full provenance trail. OKLCH alone is meaningful but harder to recognize on sight; the source hex is the identifier most teammates will look for first.
Use the URL Hash to Share Live Color Decisions
Every color change updates the URL hash as `#hex=3b82f6` or `#oklch=...` automatically. Copy the URL into a Slack thread or GitHub issue and anyone who opens it lands on the same color with the same OKLCH triple. This is more reliable than pasting an OKLCH string in chat — recipients sometimes typo the decimals or wrap the wrong precision — and lets a design-review thread reference an exact color rather than "the brand blue we discussed Tuesday." The hash is never transmitted to the server.

Frequently Asked Questions

What is OKLCH color?
OKLCH is the polar form of OKLAB, a perceptually-uniform color space published by Björn Ottosson in 2020. Channels are Lightness (0-1, also writable as 0-100%), Chroma (0 to about 0.4 depending on hue and L, unbounded above), and Hue (0-360°, identical conceptually to HSL's hue). It's derived from CIE-LAB by routing through an LMS cone-response stage with a cube-root step. CSS Color 4 added `oklch()` syntax in 2022. Tailwind v4 standardized on OKLCH for its default palette in 2025. Example: `oklch(0.629 0.193 263.4)` is Tailwind blue-500.
Is OKLCH better than HSL?
For design systems, yes. HSL's L (lightness) is geometric — derived by averaging RGB max and min — and inherits sRGB's gamma curve, so `hsl(60 100% 50%)` (yellow) looks visibly brighter than `hsl(240 100% 50%)` (blue) despite both reporting L=50%. OKLCH's L is perceptual, anchored to the OKLAB model from Ottosson 2020. The practical upshot: an OKLCH ramp at uniform L looks visually even across every hue; an HSL ramp needs hand-tuned per-hue corrections to look even. This is why Tailwind v4 migrated its default palette from HSL-based to OKLCH-based generation.
What browsers support oklch()?
All evergreen browsers as of mid-2023: Chrome and Edge 111 (March 2023), Safari 15.4 (March 2022, the earliest landing), Firefox 113 (May 2023). Combined caniuse coverage is over 94%. For the long tail — IE 11, old Safari, Android Chrome on legacy hardware — wrap your tokens in `@supports (color: oklch(0 0 0))` and provide a hex or `hsl()` fallback in the alternate branch. Build-time tools like PostCSS `postcss-oklab-function` can also inline an sRGB approximation alongside the OKLCH value at compile time.
Why use OKLCH in Tailwind v4?
Tailwind v4 (released January 2025) moved its default palette from HSL-based to OKLCH-based generation specifically because OKLCH gives perceptually-even ramps automatically. Under v3's HSL system, `red-500` and `blue-500` had visibly different perceived weights despite identical HSL L%, which forced designers to hand-tune individual stops; under v4, both look balanced because both sit at the same OKLCH L. OKLCH also unlocks Display P3 wide-gamut colors that no hex code can encode — a Tailwind v4 token like `oklch(0.65 0.25 30)` can address P3 reds that exceed sRGB. The build still emits hex fallbacks for older browsers.
Is OKLCH perceptually uniform?
Yes — that's the design intent. OKLCH inherits perceptual uniformity from OKLAB, Björn Ottosson's 2020 color space designed specifically to fix the non-uniformities in CIE-LAB (the previous best perceptually-uniform space). A fixed step in the L channel corresponds to a fixed perceived brightness step. A fixed step in C corresponds to a fixed perceived chroma step. CIELAB approximations break down around very saturated colors; OKLAB and its polar form OKLCH stay accurate across the gamut, which is why every modern design-system tool (Tailwind v4, shadcn/ui, Radix Colors v3) standardized on it.
How do you read an OKLCH value?
`oklch(L C H)` — three numbers, optionally with `/ A` for alpha. L is Lightness from 0 (black) to 1 (white); the number form and percent form are equivalent (`0.6` and `60%`). C is Chroma from 0 (gray) up to roughly 0.4 for the most saturated sRGB colors; there is no hard upper bound, wide-gamut colors can exceed it. H is Hue in degrees from 0 to 360, same as HSL (0/360 = red, 120 = green, 240 = blue). Example: `oklch(0.629 0.193 263.4)` is Tailwind blue-500 — bright, highly chromatic, in the blue arc.
What is the difference between OKLCH and LCH?
Both are polar forms (Lightness / Chroma / Hue) of a CIE-LAB-family color space. LCH is the polar form of CIE-LAB, the 1976 perceptually-uniform space. OKLCH is the polar form of OKLAB, Ottosson's 2020 update. The difference: CIE-LAB's perceptual uniformity breaks down around highly-saturated blues and purples (a documented weakness in the model), so an LCH ramp through saturated colors looks subtly uneven. OKLAB fixes this by re-deriving the matrices from a corrected LMS cone-response stage. Both ship in CSS Color 4 (`lch()` and `oklch()` syntax); for new design-system work in 2025, prefer OKLCH.
How do I convert hex to OKLCH?
The pipeline is: parse hex `#RRGGBB` to integer sRGB channels via `parseInt(hex, 16)`, normalize to 0-1, gamma-decode to linear-sRGB via the CSS Color 4 §11.2 piecewise function, multiply by the §15.1 matrix to get CIE XYZ D65, multiply by Ottosson's LMS matrix and cube-root each channel, multiply by Ottosson's OKLAB matrix to get L/a/b, then Cartesian-to-polar: `C = sqrt(a² + b²); H = atan2(b, a) * 180 / π`. The full pipeline runs in microseconds. This tool runs it live as you type — `#3b82f6` lands as `oklch(0.629 0.193 263.4)` instantly.

Related Tools

View all tools →