What this Color Converter changes
ColorConverter.jsx maps one opaque color among a HEX string, three RGB numbers, and three HSL numbers, then shows a swatch (backgroundColor: previewHex, color: suggestedText). Copy strings are colorState.hex, rgb(r, g, b), hsl(h, s%, l%), and --brand-color. Converting a value does not prove the color meets accessibility contrast requirements, renders identically on every display, matches a brand standard, or is valid for print or color-managed production.
Color formats and inputs actually supported
- HEX field
- Free text. normalizeHex: trim, strip #, 3 hex digits expanded by doubling, or 6 hex digits, then lowercase. No 8-digit HEX, no alpha suffix.
- RGB fields
- Three type=number inputs min 0 max 255. Driver when lastEdited is rgb.
- HSL fields
- h max 360, s/l max 100. Driver when lastEdited is hsl.
- Pick color
- Native type=color bound to previewHex; onChange applyColor.
- Not parsed
- Named CSS colors, rgb()/hsl() text in the HEX box, CMYK, P3, OKLCH.
How this page converts and rounds values
hexToRgb uses Number.parseInt(normalized, 16) then shifts for r/g/b. rgbToHex Math.round then clamp 0–255 and two-digit hex. rgbToHsl uses max/min/delta on channels/255, rounds h, s×100, l×100. hslToRgb uses the six 60° sectors with c/x/m and Math.round((channel+m)*255). All of that is in ColorConverter.jsx; the file does not import a color library or use canvas.
When lastEdited is hsl, RGB comes from hslToRgb(hsl.h || 0, …) which wraps hue with ((h % 360) + 360) % 360, while the HSL object shown in colorState clamps h to 0–360. A number above 360 can therefore feed RGB and the HSL readout differently. RGB lastEdited clamps channel Numbers to 0–255 without rounding in colorState.rgb; HEX still goes through rgbToHex rounding.
HEX shorthand, RGB/HSL ranges, and alpha behavior, if implemented
3-digit HEX is the only shorthand: each digit is duplicated (#f00 → ff0000). Alpha is not in normalizeHex, rgb, hsl, the picker, copy output, or the CSS snippet — there is no rgba, hsla, or #rrggbbaa. RGB out-of-range values are clamped 0–255; S/L 0–100. Empty RGB/HSL fields use || 0.
Preview and copy behavior
The large swatch uses previewHex. On a valid conversion, suggested text is getSuggestedTextColor: relativeLuminance > 0.179 → #000000, else #ffffff. Sidebar Brightness is Math.round(relativeLuminance * 100) + "%" from colorState.rgb, not HSL L. Copy buttons and the CSS pre write colorState.hex / rgb() / hsl() / --brand-color; clipboard failure sets “Copy failed. Please copy manually.” There is no download.
How to use the real controls
- Idle HEX is #6366f1. There is no Generate button. Type HEX (placeholder #6366f1), RGB R/G/B (0–255), or HSL H/S/L. lastEdited marks which trio drives colorState. Invalid HEX shows “Enter a valid HEX color such as #6366f1 or #f00.”
- Click Pick color (type=color bound to previewHex) to applyColor.
- On each HEX / RGB / HSL card, click Copy (Copied for 1.5 seconds). Under CSS values, click Copy HEX, Copy RGB, Copy HSL, or Copy CSS variable. Failure is “Copy failed. Please copy manually.”
- Click a Quick palettes swatch from buildPaletteVariants: Current, Lighter, Darker, Complement, or Soft background. Each applyColor that swatch’s hex.
- Contrast checker: Foreground color and Background color HEX, Contrast ratio, AA normal text, and AA large text (Pass / Fail). Invalid pair → ratio “—”, both badges Fail. Changing the main color without error resets FG/BG via useEffect. A valid Background HEX also applyColor.
- Click Reset or Load example — both applyColor(DEFAULT_HEX #6366f1). Color summary lists HEX, RGB, HSL, Brightness, and Suggested text (Black / White). There is no download.
Invalid color input and normalization boundaries
HEX that fails normalizeHex sets colorState.error to the #6366f1 / #f00 message, leaves the rgb/hsl React fields unchanged, sets previewHex to DEFAULT_HEX, and hardcodes suggestedText to #ffffff (getSuggestedTextColor is not called on that path). colorState.hex stays the typed hexInput, so Copy HEX / the CSS snippet can copy that invalid string while the swatch shows DEFAULT_HEX. Contrast FG/BG that fail hexToRgb yield ratio null and both badges Fail. A thrown path (catch) uses “Unable to convert this color.” with the same default preview and #ffffff suggested text.
Color conversion versus accessibility or color-managed design review
Pass/Fail on AA normal text and AA large text is ratio ≥ 4.5 and ≥ 3 from getContrastRatio of two HEX-parsed RGBs. The formula is this file’s relativeLuminance (0.03928, 12.92, 1.055, 2.4, 0.2126, 0.7152, 0.0722). It does not open WCAG documentation, measure rendered text, or apply a large-text font-size rule. There is no ICC profile, P3, HDR, or print conversion.
What this tool does not validate or guarantee
- That a color matches a brand guide, printer, or another app’s picker.
- WCAG conformance of a real page, including AAA, non-text contrast, or focus appearance.
- Browser-identical rendering of the swatch versus CSS on a user’s monitor.
- Named-color or full CSS Color Module parsing.
- A downloadable palette, ASE/GPL file, or design-token JSON export.
Privacy and browser-processing boundaries
hexToRgb, rgbToHsl, hslToRgb, and contrast math run in the tab. ColorConverter.jsx does not call trackToolEvent and does not POST HEX/RGB/HSL to a conversion API. Clipboard writes stay in the browser when permitted. Site assets, ads, and extensions remain outside this file. Refresh drops React state; there is no localStorage key.
A short color-value review checklist
- Confirm last-edited field: HEX vs RGB vs HSL, especially if the number boxes lag the swatch.
- If HEX errors, remember only 3/6 hex digits — not rgb() text or names.
- Treat 4.5 / 3 badges as this checker’s two thresholds on two HEX colors, not a site audit.
- Read Brightness as luminance×100 from this helper, not HSL lightness.
- Palette offsets are the L±18 / H+180 / S−35 rules above, not a generated brand system.
- Copy the format you will paste; this page does not write a file.
When another DevToolKit tool is more appropriate
- QR Code Generator — when you need a QR image. Its color fields only run sanitizeHexColor into qrcode; they do not convert RGB or HSL and they do not run this contrast checker.