⚡ Node.jsFrontend / Design

Color Validation in Node.js

Validate and normalise color values in Node.js — HEX (#RGB, #RRGGBB, #RRGGBBAA), RGB, RGBA, HSL, HSLA, and CSS named colors. Ideal for design system APIs, theme builders, and brand palette validation.

Also available in Python

1. Color formats supported

FormatExampleAlpha?
#RGB (shorthand)#F0F
#RRGGBB#FF5733
#RRGGBBAA#FF5733CC
rgb()rgb(255, 87, 51)
rgba()rgba(255, 87, 51, 0.8)
hsl()hsl(11, 100%, 60%)
hsla()hsla(11, 100%, 60%, 0.8)
CSS namedred, tomato, cornflowerblue

2. API response structure

Endpoint: GET /v0/color?value=…

{
  "valid": true,
  "format": "hex",
  "hex": "#FF5733",
  "rgb": { "r": 255, "g": 87, "b": 51 },
  "hsl": { "h": 11, "s": 100, "l": 60 },
  "hasAlpha": false,
  "name": "Orange Red"
}
{
  "valid": true,
  "format": "rgba",
  "hex": "#FF5733CC",
  "rgb": { "r": 255, "g": 87, "b": 51, "a": 0.8 },
  "hsl": { "h": 11, "s": 100, "l": 60, "a": 0.8 },
  "hasAlpha": true,
  "name": null
}
  1. Check valid
  2. Use hex as the canonical storage format
  3. Check hasAlpha to gate alpha-unsupported contexts
  4. Use name for human-readable display (null if not a named color)

3. Normalising colors to HEX

Accept any color format from users, normalise to #RRGGBB for storage and consistent comparison:

// All of these normalise to the same hex value
const inputs = [
  '#FF5733',
  'rgb(255, 87, 51)',
  'hsl(11, 100%, 60%)',
  'tomato',          // close CSS named color
]

const results = await Promise.all(inputs.map(c => iv.color(c)))
results.forEach(r => console.log(r.hex))
// → #FF5733 (or close approximation for named colors)
💡Always store the canonical hex value in your database, not the user-supplied string. This enables consistent equality checks and CSS variable generation.

4. Palette validation with Promise.all

import { createClient } from '@isvalid-dev/sdk'

const iv = createClient({ apiKey: process.env.ISVALID_API_KEY! })

// Validate any color format and normalise to hex
async function normaliseColor(input: string): Promise<string> {
  const result = await iv.color(input)
  if (!result.valid) throw new Error(`Invalid color: ${input}`)
  return result.hex   // always returns #RRGGBB or #RRGGBBAA
}

// Validate a brand palette
async function validatePalette(colors: Record<string, string>) {
  const entries = Object.entries(colors)
  const results = await Promise.allSettled(
    entries.map(([, value]) => iv.color(value))
  )

  const errors: Record<string, string> = {}
  const normalised: Record<string, string> = {}

  entries.forEach(([name, raw], i) => {
    const r = results[i]
    if (r.status === 'fulfilled' && r.value.valid) {
      normalised[name] = r.value.hex
    } else {
      errors[name] = `Invalid color value: ${raw}`
    }
  })

  return { valid: Object.keys(errors).length === 0, normalised, errors }
}

// Example — theme palette validation
const palette = await validatePalette({
  primary:    '#1D4ED8',
  secondary:  'rgb(99, 102, 241)',
  accent:     'hsl(262, 83%, 58%)',
  background: 'white',
  danger:     'rgba(239, 68, 68, 0.9)',
})

console.log(palette.normalised)
// {
//   primary:    '#1D4ED8',
//   secondary:  '#6366F1',
//   accent:     '#7C3AED',
//   background: '#FFFFFF',
//   danger:     '#EF4444E6',
// }

5. Edge cases

Shorthand hex expansion

// #F0F expands to #FF00FF — the API returns the full form
const result = await iv.color('#F0F')
console.log(result.hex)  // "#FF00FF"

Blocking alpha in opaque-only contexts

⚠️Some design systems or PDF renderers don't support alpha channels. Check hasAlpha before accepting the color.
const result = await iv.color(userInput)
if (result.valid && result.hasAlpha) {
  throw new Error('Alpha transparency is not supported in this context')
}

HSL value ranges

// Hue: 0–360, Saturation: 0–100%, Lightness: 0–100%
// These are invalid:
await iv.color('hsl(400, 100%, 50%)')   // hue > 360
await iv.color('hsl(0, 150%, 50%)')    // saturation > 100%
await iv.color('rgb(300, 0, 0)')        // R value > 255

6. Summary checklist

Accept any color format — validate and normalise
Store hex (#RRGGBB or #RRGGBBAA) as canonical form
Check hasAlpha for opaque-only contexts
Expand #RGB shorthand via API response
Validate brand palettes in parallel with Promise.all
Use name field for human-readable color display
Reject HSL/RGB values outside valid ranges
Return 422 with field-level errors on invalid colors

See also

Ready to integrate?

Free tier — 1,000 requests/month. No credit card required.

Get your API key →