Skip to content

Commit 5007ee9

Browse files
authored
fix: hide modal close button when not dismissible (#1641)
* fix: hide modal close button when not dismissible The close button in the modal header now only renders when the modal is dismissible. This prevents confusion where users see a close button but the modal cannot be dismissed by clicking outside or pressing Escape. Changes: - Add dismissible prop to ModalContext - Conditionally render close button in ModalHeader based on dismissible - Add tests to verify close button visibility behavior * Add changeset
1 parent 850fbd2 commit 5007ee9

File tree

5 files changed

+42
-4
lines changed

5 files changed

+42
-4
lines changed

.changeset/social-kings-cut.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"flowbite-react": patch
3+
---
4+
5+
Ensure modal close button respects dismissible prop

packages/ui/src/components/Modal/Modal.test.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,34 @@ describe("Components / Modal", () => {
2626
expect(modal).not.toBeInTheDocument();
2727
});
2828

29+
it("should not render close button when modal is not dismissible", async () => {
30+
const user = userEvent.setup();
31+
32+
render(<TestModal />);
33+
34+
await user.click(triggerButton());
35+
36+
const modal = dialog();
37+
expect(modal).toBeInTheDocument();
38+
39+
const closeButton = screen.queryByLabelText("Close");
40+
expect(closeButton).not.toBeInTheDocument();
41+
});
42+
43+
it("should render close button when modal is dismissible", async () => {
44+
const user = userEvent.setup();
45+
46+
render(<TestModal dismissible />);
47+
48+
await user.click(triggerButton());
49+
50+
const modal = dialog();
51+
expect(modal).toBeInTheDocument();
52+
53+
const closeButton = screen.queryByLabelText("Close");
54+
expect(closeButton).toBeInTheDocument();
55+
});
56+
2957
it("should append to root element when root prop is provided", async () => {
3058
const root = document.createElement("div");
3159
const user = userEvent.setup();
@@ -82,7 +110,7 @@ describe("Components / Modal", () => {
82110
it("should close `Modal` when `Space` is pressed on any of its buttons", async () => {
83111
const user = userEvent.setup();
84112

85-
render(<TestModal />);
113+
render(<TestModal dismissible />);
86114

87115
const openButton = triggerButton();
88116

packages/ui/src/components/Modal/Modal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ export const Modal = forwardRef<HTMLDivElement, ModalProps>((props, ref) => {
117117
clearTheme: props.clearTheme,
118118
applyTheme: props.applyTheme,
119119
popup,
120+
dismissible,
120121
onClose,
121122
setHeaderId,
122123
}}

packages/ui/src/components/Modal/ModalContext.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { ModalTheme } from "./Modal";
66

77
export interface ModalContextValue extends ThemingProps<ModalTheme> {
88
popup?: boolean;
9+
dismissible?: boolean;
910
setHeaderId: (id: string | undefined) => void;
1011
onClose?: () => void;
1112
}

packages/ui/src/components/Modal/ModalHeader.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export const ModalHeader = forwardRef<HTMLDivElement, ModalHeaderProps>((props,
3131
clearTheme: rootClearTheme,
3232
applyTheme: rootApplyTheme,
3333
popup,
34+
dismissible,
3435
onClose,
3536
setHeaderId,
3637
} = useModalContext();
@@ -64,9 +65,11 @@ export const ModalHeader = forwardRef<HTMLDivElement, ModalHeaderProps>((props,
6465
<Component id={headerId} className={theme.title}>
6566
{children}
6667
</Component>
67-
<button aria-label="Close" className={theme.close.base} type="button" onClick={onClose}>
68-
<OutlineXIcon aria-hidden className={theme.close.icon} />
69-
</button>
68+
{dismissible && (
69+
<button aria-label="Close" className={theme.close.base} type="button" onClick={onClose}>
70+
<OutlineXIcon aria-hidden className={theme.close.icon} />
71+
</button>
72+
)}
7073
</div>
7174
);
7275
});

0 commit comments

Comments
 (0)