diff --git a/CHANGELOG.md b/CHANGELOG.md
index 60083beaa89..9ff0dc982b7 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,6 @@
## [`master`](https://github.com/elastic/eui/tree/master)
+- Added `href` prop to `EuiBadge` ([#3009](https://github.com/elastic/eui/pull/3009))
- Added props descriptions for `EuiComboBox` ([#3007](https://github.com/elastic/eui/pull/3007))
- Exported `dateFormatAliases` as a part of the public API ([#3043](https://github.com/elastic/eui/pull/3043))
- Exported `EuiTextProps` type definition ([#3039](https://github.com/elastic/eui/pull/3039))
diff --git a/src-docs/src/views/badge/badge_button.js b/src-docs/src/views/badge/badge_button.js
index 2d65989cbff..4ed142c57be 100644
--- a/src-docs/src/views/badge/badge_button.js
+++ b/src-docs/src/views/badge/badge_button.js
@@ -41,5 +41,17 @@ export default () => (
onClick on both text and icon within badge
+
+ window.alert('Badge clicked')}
+ onClickAriaLabel="Example of disabled button badge"
+ iconOnClick={() => window.alert('Disabled badge clicked')}
+ iconOnClickAriaLabel="Example of disabled button badge"
+ data-test-sub="testExample4">
+ disabled button badge
+
+
);
diff --git a/src-docs/src/views/badge/badge_example.js b/src-docs/src/views/badge/badge_example.js
index 39d9b972990..07adb3511fa 100644
--- a/src-docs/src/views/badge/badge_example.js
+++ b/src-docs/src/views/badge/badge_example.js
@@ -71,6 +71,11 @@ const badgeButtonSnippet = [
`,
];
+import BadgeHref from './badge_href';
+const badgeHrefSource = require('!!raw-loader!./badge_href');
+const badgeHrefHtml = renderToHtml(BadgeHref);
+const badgeHrefSnippet = [''];
+
import BadgeTruncate from './badge_truncate';
const badgeTruncateSource = require('!!raw-loader!./badge_truncate');
const badgeTruncateHtml = renderToHtml(BadgeTruncate);
@@ -177,6 +182,29 @@ export const BadgeExample = {
snippet: badgeButtonSnippet,
demo: ,
},
+ {
+ title: 'Badge with href',
+ source: [
+ {
+ type: GuideSectionTypes.JS,
+ code: badgeHrefSource,
+ },
+ {
+ type: GuideSectionTypes.HTML,
+ code: badgeHrefHtml,
+ },
+ ],
+ text: (
+
+
+ Badges can also be made to render anchor tags by passing an{' '}
+ href.
+
+
+ ),
+ snippet: badgeHrefSnippet,
+ demo: ,
+ },
{
title: 'Badge groups and truncation',
source: [
diff --git a/src-docs/src/views/badge/badge_href.js b/src-docs/src/views/badge/badge_href.js
new file mode 100644
index 00000000000..d06ee4c2964
--- /dev/null
+++ b/src-docs/src/views/badge/badge_href.js
@@ -0,0 +1,38 @@
+import React from 'react';
+
+import {
+ EuiBadge,
+ EuiFlexGroup,
+ EuiFlexItem,
+} from '../../../../src/components';
+
+export default () => (
+
+
+
+ badge as an anchor
+
+
+
+
+ anchor with target specified
+
+
+
+ window.alert('Icon inside badge clicked')}
+ iconOnClickAriaLabel="Example of onClick event for icon within the anchor">
+ anchor with an icon and iconOnClick
+
+
+
+
+ disabled anchor badge
+
+
+
+);
diff --git a/src/components/badge/__snapshots__/badge.test.tsx.snap b/src/components/badge/__snapshots__/badge.test.tsx.snap
index 187c4527013..98dbc15297a 100644
--- a/src/components/badge/__snapshots__/badge.test.tsx.snap
+++ b/src/components/badge/__snapshots__/badge.test.tsx.snap
@@ -38,6 +38,46 @@ exports[`EuiBadge is rendered 1`] = `
`;
+exports[`EuiBadge is rendered with href provided 1`] = `
+
+
+
+ Content
+
+
+
+`;
+
+exports[`EuiBadge is rendered with iconOnClick and href provided 1`] = `
+
+
+
+ Content
+
+
+
+`;
+
exports[`EuiBadge is rendered with iconOnClick and onClick provided 1`] = `
-
Content
-
+
`;
diff --git a/src/components/badge/_badge.scss b/src/components/badge/_badge.scss
index d998f6060e1..ecfd6c7e712 100644
--- a/src/components/badge/_badge.scss
+++ b/src/components/badge/_badge.scss
@@ -22,8 +22,8 @@
&.euiBadge-isDisabled {
// sass-lint:disable-block no-important
// Using !important to override inline styles
+ color: makeHighContrastColor($euiButtonColorDisabled, $euiButtonColorDisabled, 2) !important;
background-color: $euiButtonColorDisabled !important;
- color: $euiButtonColorDisabledText !important;
}
&:focus-within {
@@ -46,6 +46,7 @@
text-align: inherit;
font-weight: inherit;
line-height: inherit;
+ color: inherit;
&:disabled {
cursor: not-allowed;
diff --git a/src/components/badge/badge.test.tsx b/src/components/badge/badge.test.tsx
index ecdfd943a77..ed610de5e0d 100644
--- a/src/components/badge/badge.test.tsx
+++ b/src/components/badge/badge.test.tsx
@@ -34,6 +34,16 @@ describe('EuiBadge', () => {
expect(component).toMatchSnapshot();
});
+ test('is rendered with href provided', () => {
+ const component = render(
+
+ Content
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
test('is rendered with iconOnClick provided', () => {
const component = render(
{
expect(component).toMatchSnapshot();
});
+ test('is rendered with iconOnClick and href provided', () => {
+ const component = render(
+
+ Content
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+
describe('props', () => {
describe('iconType', () => {
it('is rendered', () => {
diff --git a/src/components/badge/badge.tsx b/src/components/badge/badge.tsx
index 295769f688d..9f9bd6d9ce3 100644
--- a/src/components/badge/badge.tsx
+++ b/src/components/badge/badge.tsx
@@ -4,6 +4,7 @@ import React, {
HTMLAttributes,
MouseEventHandler,
ReactNode,
+ Ref,
} from 'react';
import classNames from 'classnames';
import { CommonProps, ExclusiveUnion, keysOf, PropsOf } from '../common';
@@ -26,6 +27,11 @@ type WithButtonProps = {
onClickAriaLabel: AriaAttributes['aria-label'];
} & Omit, 'onClick' | 'color'>;
+type WithAnchorProps = {
+ href: string;
+ target?: string;
+} & Omit, 'href' | 'color'>;
+
type WithSpanProps = Omit, 'onClick' | 'color'>;
interface WithIconOnClick {
@@ -66,7 +72,10 @@ export type EuiBadgeProps = {
closeButtonProps?: Partial>;
} & CommonProps &
ExclusiveUnion &
- ExclusiveUnion;
+ ExclusiveUnion<
+ ExclusiveUnion,
+ WithSpanProps
+ >;
// TODO - replace with variables once https://github.com/elastic/eui/issues/2731 is closed
const colorInk = '#000';
@@ -108,6 +117,8 @@ export const EuiBadge: FunctionComponent = ({
onClickAriaLabel,
iconOnClickAriaLabel,
closeButtonProps,
+ href,
+ target,
...rest
}) => {
checkValidColor(color);
@@ -160,7 +171,7 @@ export const EuiBadge: FunctionComponent = ({
const classes = classNames(
'euiBadge',
{
- 'euiBadge-isClickable': onClick && !iconOnClick,
+ 'euiBadge-isClickable': (onClick || href) && !iconOnClick,
'euiBadge-isDisabled': isDisabled,
'euiBadge--hollow': color === 'hollow',
},
@@ -172,6 +183,21 @@ export const EuiBadge: FunctionComponent = ({
'euiBadge__icon',
closeButtonProps && closeButtonProps.className
);
+ const Element = href && !isDisabled ? 'a' : 'button';
+ const relObj: {
+ href?: string;
+ target?: string;
+ onClick?:
+ | ((event: React.MouseEvent) => void)
+ | ((event: React.MouseEvent) => void);
+ } = {};
+
+ if (href && !isDisabled) {
+ relObj.href = href;
+ relObj.target = target;
+ } else if (onClick) {
+ relObj.onClick = onClick;
+ }
let optionalIcon: ReactNode = null;
if (iconType) {
@@ -209,46 +235,46 @@ export const EuiBadge: FunctionComponent = ({
);
}
- if (onClick && iconOnClick) {
+ if (iconOnClick) {
return (
{(ref, innerText) => (
-
+
)}
{optionalIcon}
);
- } else if (onClick) {
+ } else if (onClick || href) {
return (
{(ref, innerText) => (
-
+
)}
);