diff --git a/packages/eui/.loki/reference/chrome_desktop_Display_EuiBadge_EuiBadge_Custom_Colors.png b/packages/eui/.loki/reference/chrome_desktop_Display_EuiBadge_EuiBadge_Custom_Colors.png new file mode 100644 index 00000000000..d6e97633e68 Binary files /dev/null and b/packages/eui/.loki/reference/chrome_desktop_Display_EuiBadge_EuiBadge_Custom_Colors.png differ diff --git a/packages/eui/.loki/reference/chrome_mobile_Display_EuiBadge_EuiBadge_Custom_Colors.png b/packages/eui/.loki/reference/chrome_mobile_Display_EuiBadge_EuiBadge_Custom_Colors.png new file mode 100644 index 00000000000..65d50ceff5f Binary files /dev/null and b/packages/eui/.loki/reference/chrome_mobile_Display_EuiBadge_EuiBadge_Custom_Colors.png differ diff --git a/packages/eui/changelogs/upcoming/7752.md b/packages/eui/changelogs/upcoming/7752.md new file mode 100644 index 00000000000..072f090be83 --- /dev/null +++ b/packages/eui/changelogs/upcoming/7752.md @@ -0,0 +1,3 @@ +**Accessibility** + +- Improved `EuiBadge`'s ability to tell when text within the badge is selected/highlighted and selection color contrast diff --git a/packages/eui/src/components/badge/__snapshots__/badge.test.tsx.snap b/packages/eui/src/components/badge/__snapshots__/badge.test.tsx.snap index 6e8be464c31..2c41ffaaab0 100644 --- a/packages/eui/src/components/badge/__snapshots__/badge.test.tsx.snap +++ b/packages/eui/src/components/badge/__snapshots__/badge.test.tsx.snap @@ -3,7 +3,7 @@ exports[`EuiBadge is disabled 1`] = ` @@ -178,7 +178,6 @@ exports[`EuiBadge props color accent is rendered 1`] = ` exports[`EuiBadge props color accepts hex 1`] = ` = { title: 'Display/EuiBadge/EuiBadge', @@ -20,6 +20,7 @@ const meta: Meta = { // Component defaults iconSide: 'left', isDisabled: false, + color: 'default', }, }; @@ -30,4 +31,22 @@ export const Playground: Story = { args: { children: 'Badge text', }, + argTypes: { + color: { + control: 'select', + options: COLORS, + }, + }, +}; + +export const CustomColors: Story = { + parameters: { + controls: { + include: ['color', 'children', 'isDisabled'], + }, + }, + args: { + children: 'Badge text', + color: '#0000FF', + }, }; diff --git a/packages/eui/src/components/badge/badge.styles.ts b/packages/eui/src/components/badge/badge.styles.ts index bc5211b8daf..8704c3bb734 100644 --- a/packages/eui/src/components/badge/badge.styles.ts +++ b/packages/eui/src/components/badge/badge.styles.ts @@ -22,6 +22,12 @@ import { euiBadgeColors } from './color_utils'; export const euiBadgeStyles = (euiThemeContext: UseEuiTheme) => { const { euiTheme } = euiThemeContext; const badgeColors = euiBadgeColors(euiThemeContext); + const setBadgeColorVars = ( + colors: ReturnType['primary'] + ) => ` + --euiBadgeTextColor: ${colors.color}; + --euiBadgeBackgroundColor: ${colors.backgroundColor}; + `; return { euiBadge: css` @@ -39,7 +45,6 @@ export const euiBadgeStyles = (euiThemeContext: UseEuiTheme) => { white-space: nowrap; text-decoration: none; cursor: default; - background-color: transparent; border: ${euiTheme.border.width.thin} solid transparent; border-radius: ${mathWithUnits( euiTheme.border.radius.medium, @@ -49,6 +54,25 @@ export const euiBadgeStyles = (euiThemeContext: UseEuiTheme) => { So, make the text left aligned to ensure all badges line up the same */ ${logicalTextAlignCSS('left')} + /* Colors - inherit from CSS variables, which can be set via inline style */ + color: var(--euiBadgeTextColor, ${badgeColors.default.color}); + background-color: var( + --euiBadgeBackgroundColor, + ${badgeColors.default.backgroundColor} + ); + + /* Ensure that selected text is always visible by inverting badge and text colors */ + *::selection { + color: var( + --euiBadgeBackgroundColor, + ${badgeColors.default.backgroundColor} + ); + background-color: var( + --euiBadgeTextColor, + ${badgeColors.default.color} + ); + } + &:focus-within { ${euiFocusRing(euiThemeContext)} } @@ -75,25 +99,23 @@ export const euiBadgeStyles = (euiThemeContext: UseEuiTheme) => { `, // Colors - default: css(badgeColors.default), + default: css(setBadgeColorVars(badgeColors.default)), hollow: css` - color: ${badgeColors.hollow.color}; - background-color: ${badgeColors.hollow.backgroundColor}; + ${setBadgeColorVars(badgeColors.hollow)} border-color: ${badgeColors.hollow.borderColor}; `, - primary: css(badgeColors.primary), - accent: css(badgeColors.accent), - warning: css(badgeColors.warning), - danger: css(badgeColors.danger), - success: css(badgeColors.success), + primary: css(setBadgeColorVars(badgeColors.primary)), + accent: css(setBadgeColorVars(badgeColors.accent)), + warning: css(setBadgeColorVars(badgeColors.warning)), + danger: css(setBadgeColorVars(badgeColors.danger)), + success: css(setBadgeColorVars(badgeColors.success)), disabled: css` - /* stylelint-disable declaration-no-important */ + ${setBadgeColorVars(badgeColors.disabled)} - /* Using !important to override inline styles */ - color: ${badgeColors.disabled.color} !important; - background-color: ${badgeColors.disabled.backgroundColor} !important; - - /* stylelint-enable declaration-no-important */ + /* Override selection color, since disabled badges have rgba backgrounds with opacity */ + *::selection { + color: ${euiTheme.colors.emptyShade}; + } `, // Content wrapper diff --git a/packages/eui/src/components/badge/badge.test.tsx b/packages/eui/src/components/badge/badge.test.tsx index 00d0af9c924..cd8df65b7d4 100644 --- a/packages/eui/src/components/badge/badge.test.tsx +++ b/packages/eui/src/components/badge/badge.test.tsx @@ -154,12 +154,16 @@ describe('EuiBadge', () => { ); expect(container.firstChild).toMatchSnapshot(); + // NOTE: jsdom currently does not support CSS variables (@see https://github.com/testing-library/jest-dom/issues/322) + // We're relying on visual regression tests here instead }); it('accepts hex', () => { const { container } = render(Content); expect(container.firstChild).toMatchSnapshot(); + // NOTE: jsdom currently does not support CSS variables (@see https://github.com/testing-library/jest-dom/issues/322) + // We're relying on visual regression tests here instead }); }); diff --git a/packages/eui/src/components/badge/badge.tsx b/packages/eui/src/components/badge/badge.tsx index 3e3bac321f2..735576b30b6 100644 --- a/packages/eui/src/components/badge/badge.tsx +++ b/packages/eui/src/components/badge/badge.tsx @@ -132,6 +132,8 @@ export const EuiBadge: FunctionComponent = ({ const euiTheme = useEuiTheme(); const customColorStyles = useMemo(() => { + // Disabled badges should not have custom colors + if (isDisabled) return style; // Named colors set their styles via Emotion CSS and not inline styles if (isNamedColor) return style; @@ -151,8 +153,8 @@ export const EuiBadge: FunctionComponent = ({ } return { - backgroundColor: color, - color: textColor, + '--euiBadgeBackgroundColor': color, + '--euiBadgeTextColor': textColor, ...style, }; } catch (err) { @@ -164,14 +166,17 @@ export const EuiBadge: FunctionComponent = ({ ); } } - }, [color, isNamedColor, style, euiTheme]); + }, [color, isNamedColor, isDisabled, style, euiTheme]); const styles = useEuiMemoizedStyles(euiBadgeStyles); const cssStyles = [ styles.euiBadge, - isNamedColor && styles[color as BadgeColor], - (onClick || href) && !iconOnClick && styles.clickable, - isDisabled && styles.disabled, + ...(isDisabled + ? [styles.disabled] + : [ + isNamedColor && styles[color as BadgeColor], + !iconOnClick && (onClick || href) && styles.clickable, + ]), ]; const textCssStyles = [ styles.text.euiBadge__text,