Skip to content

Instantly share code, notes, and snippets.

@renoirb
Last active October 22, 2025 16:00
Show Gist options
  • Save renoirb/fccec5d60caed020d01bb164d3de8f7d to your computer and use it in GitHub Desktop.
Save renoirb/fccec5d60caed020d01bb164d3de8f7d to your computer and use it in GitHub Desktop.
Calculate and manage color contrast between text and its background color

Color Contrast

In Design Systems use, either created ad-hoc, and managed from within a web application, when we want to support flexibiilty in color management, one recurring theme is the color variation to use as the background for a given color. Tailwind CSS helps managing some of the coplexity by allowing class names, but we still end up with the same problem. A Text color might be better with a very specific level of luminosity of the background color.

export type HexColor = `#${string}`;
/**
* Calculate relative luminance (WCAG formula)
* Returns value between 0 (black) and 1 (white)
*/
export const getLuminance = (r: number, g: number, b: number): number => {
const [rs, gs, bs] = [r, g, b].map((c) => {
const srgb = c / 255;
return srgb <= 0.03928
? srgb / 12.92
: Math.pow((srgb + 0.055) / 1.055, 2.4);
});
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
};
/**
* Convert hex color to RGB values as a 3 items long tuple.
*/
export const hexToRgb = (hex: HexColor): [number, number, number] => {
const clean = hex.replace('#', '');
const bigint = parseInt(
clean.length === 3
? clean
.split('')
.map((c) => c + c)
.join('')
: clean,
16
);
return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
};
/**
* Get contrasting text color (black or white) for given background.
*
* @param bgColor - Background color in hex format
* @returns '#000000' or '#ffffff'
*
* @example Usage Example
* ```typescript
* const fillColor: HexColor = '#ff6b35';
* getContrastingTextColor(fillColor); // Returns '#000000' or '#ffffff'
* ```
*/
export const getContrastingTextColor = (
bgColor: HexColor,
lightTextColor: HexColor = '#000',
darkTextColor: HexColor = '#FFF',
): HexColor => {
const [r, g, b] = hexToRgb(bgColor);
const luminance = getLuminance(r, g, b);
// WCAG threshold: 0.5 works well for most cases
return luminance > 0.5 ? darkTextColor : lightTextColor;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment