You can utilize Max Contrast to help you define a foreground color that passes minimum contrast threshold. This can be helpful when you’re getting custom color (f.e. defined by user) or you’re solving outlier use cases with less frequent color tokens.
background-color: color.statusGreenBase;
color: color.statusOnGreenBase;
How to use
Simply pass the color and theme to your styled or react component like so:
// Example with styled component
color: ${({ theme, color }) => maxContrast(color, theme);
How it works
import { type BoxShadow, type Color, type Theme } from '@productboard/nucleus/theme';
export const getThemeToken = <
T extends string | number | symbol,
O extends Record<string, unknown>,
>(
token: T,
object: O,
) => {
if (token in object) return object[token as unknown as keyof O];
return token;
};
export const getBoxShadow = (boxShadow: string | BoxShadow, theme: Theme): string =>
getThemeToken(boxShadow, theme.boxShadow);
export const getColor = (color: string | Color, theme: Theme) => {
if (color.startsWith('#')) return color;
return getThemeToken(color, theme.color);
};
Function imports the two default choices of foreground colors in Nucleus. Values of color tokens can change depending on theme so it’s better to use these rather than absolutes.
export function maxContrast(color: string | Color, theme: Theme) {
const hexCode = getColor(color, theme);
// based on APCA™ 0.98G middle contrast BG color
const flipYs = 0.342;
const trc = 2.4;
const Rco = 0.2126729;
const Gco = 0.7151522;
const Bco = 0.072175;
// Extract RGB components from hex
const Rs = parseInt(hexCode.slice(1, 3), 16);
const Gs = parseInt(hexCode.slice(3, 5), 16);
const Bs = parseInt(hexCode.slice(5, 7), 16);
// Calculate luminance
const Ys =
(Rs / 255.0) ** trc * Rco +
(Gs / 255.0) ** trc * Gco +
(Bs / 255.0) ** trc * Bco;
return Ys < flipYs ? theme.color.foregroundInverted : theme.color.foregroundBase;
}
It then calculates your color’s total luminance and checks it against the minimum recommended threshold. Flip point of the scale will then tell us which of the two global colors has better contrast.