diff --git a/.changeset/three-years-visit.md b/.changeset/three-years-visit.md
new file mode 100644
index 00000000000..909567a3cf9
--- /dev/null
+++ b/.changeset/three-years-visit.md
@@ -0,0 +1,5 @@
+---
+"@salt-ds/core": minor
+---
+
+Added `disableScroll` prop to FloatingComponent.
diff --git a/packages/core/src/__tests__/__e2e__/utils/useFloatingUI.cy.tsx b/packages/core/src/__tests__/__e2e__/utils/useFloatingUI.cy.tsx
index e2d89260d73..0897a2684de 100644
--- a/packages/core/src/__tests__/__e2e__/utils/useFloatingUI.cy.tsx
+++ b/packages/core/src/__tests__/__e2e__/utils/useFloatingUI.cy.tsx
@@ -11,11 +11,13 @@ const TestComponent = ({
contentId = "test-1-content",
focusManager,
open = true,
+ disableScroll = false,
}: {
id?: string;
contentId?: string;
focusManager?: boolean;
open?: boolean;
+ disableScroll?: boolean;
}) => {
const { Component: FloatingComponent } = useFloatingComponent();
const { context } = useFloatingUI({
@@ -26,6 +28,7 @@ const TestComponent = ({
@@ -84,4 +87,28 @@ describe("Use useFloatingComponent", () => {
);
});
});
+ describe("without disableScroll", () => {
+ it("the document body should not have hidden overflow", () => {
+ mount(
+
+
+ ,
+ );
+
+ cy.document().its("documentElement.style.overflow").should("equal", "");
+ });
+ });
+ describe("with disableScroll", () => {
+ it("the document body should have hidden overflow", () => {
+ mount(
+
+
+ ,
+ );
+
+ cy.document()
+ .its("documentElement.style.overflow")
+ .should("equal", "hidden");
+ });
+ });
});
diff --git a/packages/core/src/dialog/Dialog.tsx b/packages/core/src/dialog/Dialog.tsx
index 7e1b546146f..72b3a1e2101 100644
--- a/packages/core/src/dialog/Dialog.tsx
+++ b/packages/core/src/dialog/Dialog.tsx
@@ -148,6 +148,7 @@ export const Dialog = forwardRef(
ref={floatingRef}
width={elements.floating?.offsetWidth}
height={elements.floating?.offsetHeight}
+ disableScroll={true}
focusManagerProps={{
context: context,
initialFocus,
diff --git a/packages/core/src/utils/useFloatingUI/useFloatingUI.tsx b/packages/core/src/utils/useFloatingUI/useFloatingUI.tsx
index 1f6a45e358d..ce7eb7e4244 100644
--- a/packages/core/src/utils/useFloatingUI/useFloatingUI.tsx
+++ b/packages/core/src/utils/useFloatingUI/useFloatingUI.tsx
@@ -13,12 +13,14 @@ import {
shift,
useFloating,
} from "@floating-ui/react";
+import { useWindow } from "@salt-ds/window";
import {
type ComponentPropsWithoutRef,
type ReactNode,
createContext,
forwardRef,
useContext,
+ useEffect,
useMemo,
} from "react";
import { SaltProvider, SaltProviderNext, useTheme } from "../../salt-provider";
@@ -45,6 +47,10 @@ export interface FloatingComponentProps
width?: number;
height?: number;
position?: Strategy;
+ /**
+ * Disables scrolling the document body while the floating component is open.
+ */
+ disableScroll?: boolean;
}
const DefaultFloatingComponent = forwardRef<
@@ -59,6 +65,7 @@ const DefaultFloatingComponent = forwardRef<
width,
height,
focusManagerProps,
+ disableScroll,
...rest
} = props;
const style = {
@@ -69,8 +76,24 @@ const DefaultFloatingComponent = forwardRef<
const { themeNext } = useTheme();
+ const targetWindow = useWindow();
+
const ChosenSaltProvider = themeNext ? SaltProviderNext : SaltProvider;
+ useEffect(() => {
+ if (!disableScroll || !targetWindow) {
+ return;
+ }
+ if (open) {
+ targetWindow.document.documentElement.style.overflow = "hidden";
+ } else {
+ targetWindow.document.documentElement.style.removeProperty("overflow");
+ }
+ return () => {
+ targetWindow.document.documentElement.style.removeProperty("overflow");
+ };
+ }, [disableScroll, open, targetWindow]);
+
if (focusManagerProps && open) {
return (