diff --git a/packages/web-react/src/components/Modal/ModalCloseButton.tsx b/packages/web-react/src/components/Modal/ModalCloseButton.tsx
new file mode 100644
index 0000000000..ac13400763
--- /dev/null
+++ b/packages/web-react/src/components/Modal/ModalCloseButton.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import { ModalCloseButtonProps } from '../../types';
+import { Icon } from '../Icon';
+import { VisuallyHidden } from '../VisuallyHidden';
+import { Button } from '../Button';
+
+const ModalCloseButton = ({ label = 'Close', onClose, id, isOpen, ...restProps }: ModalCloseButtonProps) => (
+
+);
+
+export default ModalCloseButton;
diff --git a/packages/web-react/src/components/Modal/ModalHeader.tsx b/packages/web-react/src/components/Modal/ModalHeader.tsx
index b994c47593..e8f28e5f7a 100644
--- a/packages/web-react/src/components/Modal/ModalHeader.tsx
+++ b/packages/web-react/src/components/Modal/ModalHeader.tsx
@@ -1,10 +1,8 @@
import classNames from 'classnames';
import React from 'react';
import { useStyleProps } from '../../hooks';
-import { ClickEvent, ModalHeaderProps } from '../../types';
-import { Button } from '../Button';
-import { Icon } from '../Icon';
-import { VisuallyHidden } from '../VisuallyHidden';
+import { ModalHeaderProps } from '../../types';
+import ModalCloseButton from './ModalCloseButton';
import { useModalContext } from './ModalContext';
import { useModalStyleProps } from './useModalStyleProps';
@@ -22,18 +20,7 @@ const ModalHeader = (props: ModalHeaderProps) => {
{children}
)}
-
+
);
};
diff --git a/packages/web-react/src/components/Modal/__tests__/ModalCloseButton.test.tsx b/packages/web-react/src/components/Modal/__tests__/ModalCloseButton.test.tsx
new file mode 100644
index 0000000000..8181e98549
--- /dev/null
+++ b/packages/web-react/src/components/Modal/__tests__/ModalCloseButton.test.tsx
@@ -0,0 +1,50 @@
+import '@testing-library/jest-dom';
+import { fireEvent, render } from '@testing-library/react';
+import React from 'react';
+import { classNamePrefixProviderTest } from '../../../../tests/providerTests/classNamePrefixProviderTest';
+import { restPropsTest } from '../../../../tests/providerTests/restPropsTest';
+import { stylePropsTest } from '../../../../tests/providerTests/stylePropsTest';
+import ModalCloseButton from '../ModalCloseButton';
+
+describe('ModalCloseButton', () => {
+ classNamePrefixProviderTest(ModalCloseButton, 'Button');
+
+ stylePropsTest(ModalCloseButton);
+
+ restPropsTest(ModalCloseButton, 'button');
+
+ it('should have icon', () => {
+ const dom = render( {}} />);
+
+ expect(dom.container.querySelector('svg')).toBeDefined();
+ });
+
+ it('should have visually hidden label', () => {
+ const dom = render( {}} />);
+
+ expect(dom.container.querySelector('button > span')?.textContent).toBe('close');
+ expect(dom.container.querySelector('button > span')).toHaveClass('accessibility-hidden');
+ });
+
+ it('should be square', () => {
+ const dom = render( {}} />);
+
+ expect(dom.container.querySelector('button')).toHaveClass('Button--square');
+ });
+
+ it('should have tertiary color', () => {
+ const dom = render( {}} />);
+
+ expect(dom.container.querySelector('button')).toHaveClass('Button--tertiary');
+ });
+
+ it('should handle on close click', () => {
+ const mockedOnClose = jest.fn();
+ const dom = render();
+
+ const button = dom.getByRole('button');
+ fireEvent.click(button);
+
+ expect(mockedOnClose).toHaveBeenCalled();
+ });
+});
diff --git a/packages/web-react/src/components/Modal/index.ts b/packages/web-react/src/components/Modal/index.ts
index 75793a7bab..d074b7372c 100644
--- a/packages/web-react/src/components/Modal/index.ts
+++ b/packages/web-react/src/components/Modal/index.ts
@@ -1,7 +1,8 @@
export { default as Modal } from './Modal';
-export { default as ModalDialog } from './ModalDialog';
export { default as ModalBody } from './ModalBody';
-export { default as ModalHeader } from './ModalHeader';
-export { default as ModalFooter } from './ModalFooter';
+export { default as ModalCloseButton } from './ModalCloseButton';
export * from './ModalContext';
+export { default as ModalDialog } from './ModalDialog';
+export { default as ModalFooter } from './ModalFooter';
+export { default as ModalHeader } from './ModalHeader';
export * from './useModalStyleProps';
diff --git a/packages/web-react/src/types/modal.ts b/packages/web-react/src/types/modal.ts
index d51ae3f9f8..8e55032827 100644
--- a/packages/web-react/src/types/modal.ts
+++ b/packages/web-react/src/types/modal.ts
@@ -1,13 +1,13 @@
-import { ElementType, ComponentPropsWithRef } from 'react';
+import { ComponentPropsWithRef, ElementType } from 'react';
import {
+ AlignmentXDictionaryType,
ChildrenProps,
ClickEvent,
OmittedExtendedUnsafeStyleProps,
- StyleProps,
- SpiritDivElementProps,
SpiritDialogElementProps,
+ SpiritDivElementProps,
SpiritElementProps,
- AlignmentXDictionaryType,
+ StyleProps,
} from './shared';
export type ModalDialogElementType = 'article' | 'form';
@@ -17,6 +17,11 @@ export type ModalDialogHandlingProps = {
onClose: (event: ClickEvent) => void;
};
+export interface ModalCloseButtonProps extends ModalDialogHandlingProps {
+ id: string;
+ label: string;
+}
+
export type ModalDialogBaseProps = {
elementType?: E;
isExpandedOnMobile?: boolean;