Max Contrast

Send the background color, return whichever recommended variable passed the contrast threshold.

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.

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

Graph of the Max Contrast calculation

 


                                                        
                                                        
                                                            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.