diff --git a/CHANGELOG.md b/CHANGELOG.md
index 148b6546c47..073b2645091 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
- Updated `EuiComboBox` to WAI-ARIA 1.2 pattern and improved keyboard navigation ([#5636](https://github.com/elastic/eui/pull/5636))
- Added `readOnly` prop to `EuiMarkdownEditor` ([#5627](https://github.com/elastic/eui/pull/5627))
+- Added support for supplying `breadcrumbs` and `breadcrumbProps` directly to `EuiPageHeader` ([#5634](https://github.com/elastic/eui/pull/5634))
+- Extended props of `EuiBreadcrumb` to include `HTMLElement` and `color` inherited from `EuiLink` ([#5634](https://github.com/elastic/eui/pull/5634))
## [`49.0.0`](https://github.com/elastic/eui/tree/v49.0.0)
diff --git a/src-docs/src/views/breadcrumbs/breadcrumbs.js b/src-docs/src/views/breadcrumbs/breadcrumbs.js
index fe8e9ac9e73..225f6be9ac4 100644
--- a/src-docs/src/views/breadcrumbs/breadcrumbs.js
+++ b/src-docs/src/views/breadcrumbs/breadcrumbs.js
@@ -13,7 +13,6 @@ export default () => {
{
text: 'Animals',
href: '#',
- color: 'primary',
onClick: (e) => {
e.preventDefault();
},
diff --git a/src-docs/src/views/breadcrumbs/breadcrumbs_example.js b/src-docs/src/views/breadcrumbs/breadcrumbs_example.js
index aa9428e7242..df01a1d5adb 100644
--- a/src-docs/src/views/breadcrumbs/breadcrumbs_example.js
+++ b/src-docs/src/views/breadcrumbs/breadcrumbs_example.js
@@ -25,6 +25,9 @@ import Max from './max';
import { EuiCallOut } from '../../../../src/components/call_out';
const maxSource = require('!!raw-loader!./max');
+import Color from './color';
+const colorSource = require('!!raw-loader!./color');
+
const breadcrumpProps = {
EuiBreadcrumbs,
EuiBreadcrumb: BreadcrumbProps,
@@ -241,5 +244,30 @@ export const BreadcrumbsExample = {
],
demo: ,
},
+ {
+ title: 'Color for emphasis',
+ text: (
+ <>
+
+ Each breadcrumb extends the color options from{' '}
+
+ EuiLink
+ {' '}
+ when either an href or onClick{' '}
+ is applied . You can change the default color of a breadcrumb to add
+ emphasis or indicate state like {"'danger'"} for
+ an error. However, use caution not to use color alone.
+
+ Breadcrumbs are useful for
+ tracking in-page flows that{' '}
+ are not part of the entire application architecture
+ . To make this easy EuiPageHeader provides a{' '}
+ breadcrumbs prop that accepts the same
+ configuration as EuiBreadrumbs.breadcrumbs.
+
diff --git a/src/components/page/page_header/page_header.tsx b/src/components/page/page_header/page_header.tsx
index 6211d7bf78d..e6574eae86d 100644
--- a/src/components/page/page_header/page_header.tsx
+++ b/src/components/page/page_header/page_header.tsx
@@ -11,7 +11,7 @@ import classNames from 'classnames';
import { CommonProps, keysOf } from '../../common';
import {
EuiPageHeaderContent,
- EuiPageHeaderContentProps,
+ _EuiPageHeaderContentProps,
} from './page_header_content';
import {
_EuiPageRestrictWidth,
@@ -27,20 +27,21 @@ const paddingSizeToClassNameMap = {
export const PADDING_SIZES = keysOf(paddingSizeToClassNameMap);
-export type EuiPageHeaderProps = CommonProps &
- HTMLAttributes &
- EuiPageHeaderContentProps &
- _EuiPageRestrictWidth & {
- /**
- * Adjust the padding.
- * When using this setting it's best to be consistent throughout all similar usages
- */
- paddingSize?: typeof PADDING_SIZES[number];
- /**
- * Adds a bottom border to separate it from the content after
- */
- bottomBorder?: boolean;
- };
+export interface EuiPageHeaderProps
+ extends CommonProps,
+ HTMLAttributes,
+ _EuiPageHeaderContentProps,
+ _EuiPageRestrictWidth {
+ /**
+ * Adjust the padding.
+ * When using this setting it's best to be consistent throughout all similar usages
+ */
+ paddingSize?: typeof PADDING_SIZES[number];
+ /**
+ * Adds a bottom border to separate it from the content after
+ */
+ bottomBorder?: boolean;
+}
export const EuiPageHeader: FunctionComponent = ({
className,
@@ -61,6 +62,8 @@ export const EuiPageHeader: FunctionComponent = ({
iconProps,
tabs,
tabsProps,
+ breadcrumbs,
+ breadcrumbProps,
description,
rightSideItems,
rightSideGroupProps,
@@ -109,6 +112,8 @@ export const EuiPageHeader: FunctionComponent = ({
description={description}
rightSideItems={rightSideItems}
rightSideGroupProps={rightSideGroupProps}
+ breadcrumbs={breadcrumbs}
+ breadcrumbProps={breadcrumbProps}
>
{children}
diff --git a/src/components/page/page_header/page_header_content.test.tsx b/src/components/page/page_header/page_header_content.test.tsx
index fc72ced4a6c..049441b3602 100644
--- a/src/components/page/page_header/page_header_content.test.tsx
+++ b/src/components/page/page_header/page_header_content.test.tsx
@@ -15,6 +15,7 @@ import {
EuiPageHeaderContent,
EuiPageHeaderContentProps,
} from './page_header_content';
+import { EuiBreadcrumb } from '../../breadcrumbs';
const tabs: EuiPageHeaderContentProps['tabs'] = [
{
@@ -31,6 +32,23 @@ const rightSideItems: EuiPageHeaderContentProps['rightSideItems'] = [
,
];
+const breadcrumbs: EuiBreadcrumb[] = [
+ {
+ text: 'Animals',
+ href: '#',
+ onClick: (e: React.MouseEvent) => {
+ e.preventDefault();
+ console.log('You clicked Animals');
+ },
+ 'data-test-subj': 'breadcrumbsAnimals',
+ className: 'customClass',
+ color: 'primary',
+ },
+ {
+ text: 'Edit',
+ },
+];
+
describe('EuiPageHeaderContent', () => {
test('is rendered', () => {
const component = render();
@@ -96,6 +114,19 @@ describe('EuiPageHeaderContent', () => {
});
});
+ describe('breadcrumbs', () => {
+ test('is rendered', () => {
+ const component = render(
+
+ );
+
+ expect(component).toMatchSnapshot();
+ });
+ });
+
describe('children', () => {
test('is rendered', () => {
const component = render(
diff --git a/src/components/page/page_header/page_header_content.tsx b/src/components/page/page_header/page_header_content.tsx
index 993a5aa3051..0d92ac5d313 100644
--- a/src/components/page/page_header/page_header_content.tsx
+++ b/src/components/page/page_header/page_header_content.tsx
@@ -18,6 +18,7 @@ import { EuiTitle, EuiTitleProps } from '../../title';
import { EuiText } from '../../text';
import { useIsWithinBreakpoints } from '../../../services/hooks';
import { EuiScreenReaderOnly } from '../../accessibility';
+import { EuiBreadcrumbs, EuiBreadcrumbsProps } from '../../breadcrumbs';
export const ALIGN_ITEMS = ['top', 'bottom', 'center', 'stretch'] as const;
@@ -29,7 +30,7 @@ type Tab = EuiTabProps & {
label: ReactNode;
};
-export type EuiPageHeaderContentTitle = {
+export interface EuiPageHeaderContentTitle {
/**
* Wrapped in an `H1` so choose appropriately.
* A simple string is best
@@ -47,9 +48,17 @@ export type EuiPageHeaderContentTitle = {
* Additional EuiIcon props to apply to the optional icon
*/
iconProps?: Partial>;
-};
+ /**
+ * Optional array breadcrumbs that render before the `pageTitle`
+ */
+ breadcrumbs?: EuiBreadcrumbsProps['breadcrumbs'];
+ /**
+ * Adjust the props of [EuiBreadcrumbs](#/navigation/breadcrumbs)
+ */
+ breadcrumbProps?: Partial>;
+}
-export type EuiPageHeaderContentTabs = {
+export interface EuiPageHeaderContentTabs {
/**
* In-app navigation presented as large borderless tabs.
* Accepts an array of `EuiTab` objects;
@@ -60,50 +69,54 @@ export type EuiPageHeaderContentTabs = {
* Extends `EuiTabs`
*/
tabsProps?: Omit;
-};
+}
/**
* The left side can either be a title with optional description and/or icon;
* Or a list of tabs,
* Or a custom node
*/
-type EuiPageHeaderContentLeft = EuiPageHeaderContentTitle &
- EuiPageHeaderContentTabs & {
- /**
- * Position is dependent on existing with a `pageTitle` or `tabs`
- * Automatically get wrapped in a single paragraph tag inside an EuiText block
- */
- description?: string | ReactNode;
- };
+interface EuiPageHeaderContentLeft
+ extends EuiPageHeaderContentTitle,
+ EuiPageHeaderContentTabs {
+ /**
+ * Position is dependent on existing with a `pageTitle` or `tabs`
+ * Automatically get wrapped in a single paragraph tag inside an EuiText block
+ */
+ description?: string | ReactNode;
+}
+
+export interface _EuiPageHeaderContentProps extends EuiPageHeaderContentLeft {
+ /**
+ * Set to false if you don't want the children to stack at small screen sizes.
+ * Set to `reverse` to display the right side content first for the sake of hierarchy (like global time)
+ */
+ responsive?: boolean | 'reverse';
+ /**
+ * Vertical alignment of the left and right side content;
+ * Default is `middle` for custom content, but `top` for when `pageTitle` or `tabs` are included
+ */
+ alignItems?: typeof ALIGN_ITEMS[number];
+ /**
+ * Pass custom an array of content to this side usually up to 3 buttons.
+ * The first button should be primary, usually with `fill` and will be visually displayed as the last item,
+ * but first in the tab order
+ */
+ rightSideItems?: ReactNode[];
+ /**
+ * Additional EuiFlexGroup props to pass to the container of the `rightSideItems`
+ */
+ rightSideGroupProps?: Partial;
+ /**
+ * Custom children will be rendered before the `tabs` unless no `pageTitle` is present, then it will be the last item
+ */
+ children?: ReactNode;
+}
-export type EuiPageHeaderContentProps = CommonProps &
- HTMLAttributes &
- EuiPageHeaderContentLeft & {
- /**
- * Set to false if you don't want the children to stack at small screen sizes.
- * Set to `reverse` to display the right side content first for the sake of hierarchy (like global time)
- */
- responsive?: boolean | 'reverse';
- /**
- * Vertical alignment of the left and right side content;
- * Default is `middle` for custom content, but `top` for when `pageTitle` or `tabs` are included
- */
- alignItems?: typeof ALIGN_ITEMS[number];
- /**
- * Pass custom an array of content to this side usually up to 3 buttons.
- * The first button should be primary, usually with `fill` and will be visually displayed as the last item,
- * but first in the tab order
- */
- rightSideItems?: ReactNode[];
- /**
- * Additional EuiFlexGroup props to pass to the container of the `rightSideItems`
- */
- rightSideGroupProps?: Partial;
- /**
- * Custom children will be rendered before the `tabs` unless no `pageTitle` is present, then it will be the last item
- */
- children?: ReactNode;
- };
+export interface EuiPageHeaderContentProps
+ extends CommonProps,
+ HTMLAttributes,
+ _EuiPageHeaderContentProps {}
export const EuiPageHeaderContent: FunctionComponent = ({
className,
@@ -114,6 +127,8 @@ export const EuiPageHeaderContent: FunctionComponent
tabs,
tabsProps,
description,
+ breadcrumbs,
+ breadcrumbProps,
alignItems = 'top',
responsive = true,
rightSideItems,
@@ -140,6 +155,13 @@ export const EuiPageHeaderContent: FunctionComponent
);
}
+ const optionalBreadcrumbs = breadcrumbs ? (
+ <>
+
+
+ >
+ ) : undefined;
+
let pageTitleNode;
if (pageTitle) {
const icon = iconType ? (
@@ -277,6 +299,7 @@ export const EuiPageHeaderContent: FunctionComponent
return alignItems === 'top' || isResponsiveBreakpoint ? (