From b6f4e32240be805556cbb12e708e6d487a6e3326 Mon Sep 17 00:00:00 2001 From: Rahman Date: Mon, 11 Aug 2025 19:36:40 +0200 Subject: [PATCH 1/2] fix(datagrid-web): preventScroll on column selector focus --- packages/pluggableWidgets/datagrid-web/CHANGELOG.md | 4 ++++ packages/pluggableWidgets/datagrid-web/package.json | 2 +- .../datagrid-web/src/components/ColumnSelector.tsx | 4 ++-- packages/pluggableWidgets/datagrid-web/src/package.xml | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/pluggableWidgets/datagrid-web/CHANGELOG.md b/packages/pluggableWidgets/datagrid-web/CHANGELOG.md index 59cfbca641..311e685ba2 100644 --- a/packages/pluggableWidgets/datagrid-web/CHANGELOG.md +++ b/packages/pluggableWidgets/datagrid-web/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Fixed + +- We fixed an issue where the datagrid's horizontal scrollbar would unexpectedly jump to the right when the column selector was enabled. + ## [3.0.1] - 2025-08-05 ### Fixed diff --git a/packages/pluggableWidgets/datagrid-web/package.json b/packages/pluggableWidgets/datagrid-web/package.json index 8dd955fc0d..6a48b6b060 100644 --- a/packages/pluggableWidgets/datagrid-web/package.json +++ b/packages/pluggableWidgets/datagrid-web/package.json @@ -1,7 +1,7 @@ { "name": "@mendix/datagrid-web", "widgetName": "Datagrid", - "version": "3.0.1", + "version": "3.0.2", "description": "", "copyright": "© Mendix Technology BV 2025. All rights reserved.", "license": "Apache-2.0", diff --git a/packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx b/packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx index 7d22f3d6c6..ec99b642e9 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx @@ -56,9 +56,9 @@ export function ColumnSelector(props: ColumnSelectorProps): ReactElement { (refs.floating?.current?.querySelector("li") as HTMLElement)?.focus(); }, 10); } else { - // focus back to the button when closing + // focus back to the button when closing (prevent scroll to prevent horizontal scroll jumps on initial render) setTimeout(() => { - (refs.reference?.current as HTMLElement)?.focus(); + (refs.reference?.current as HTMLElement)?.focus({ preventScroll: true }); }, 10); } }, [show]); diff --git a/packages/pluggableWidgets/datagrid-web/src/package.xml b/packages/pluggableWidgets/datagrid-web/src/package.xml index b224969655..106bea1dc1 100644 --- a/packages/pluggableWidgets/datagrid-web/src/package.xml +++ b/packages/pluggableWidgets/datagrid-web/src/package.xml @@ -1,6 +1,6 @@ - + From c71b2eadae73238973bfda464f269b5b5240b2d6 Mon Sep 17 00:00:00 2001 From: Rahman Date: Tue, 12 Aug 2025 15:30:04 +0200 Subject: [PATCH 2/2] fix(datagrid-web): utilize floatingui focus manager --- .../src/components/ColumnSelector.tsx | 34 ++++++++----------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx b/packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx index ec99b642e9..27d84e074f 100644 --- a/packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx +++ b/packages/pluggableWidgets/datagrid-web/src/components/ColumnSelector.tsx @@ -1,5 +1,13 @@ -import { autoUpdate, size, useClick, useDismiss, useFloating, useInteractions } from "@floating-ui/react"; -import { createElement, ReactElement, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; +import { + FloatingFocusManager, + autoUpdate, + size, + useClick, + useDismiss, + useFloating, + useInteractions +} from "@floating-ui/react"; +import { createElement, ReactElement, useEffect, useMemo, useState } from "react"; import { flushSync } from "react-dom"; import { GridColumn } from "../typings/GridColumn"; import { FaEye } from "./icons/FaEye"; @@ -15,7 +23,6 @@ export function ColumnSelector(props: ColumnSelectorProps): ReactElement { const { visibleLength } = props; const [show, setShow] = useState(false); const [maxHeight, setMaxHeight] = useState(0); - const buttonRef = useRef(null); const { refs, floatingStyles, context, update } = useFloating({ open: show, placement: "bottom-end", @@ -49,20 +56,6 @@ export function ColumnSelector(props: ColumnSelectorProps): ReactElement { const firstHidableColumnIndex = useMemo(() => props.columns.findIndex(c => c.canHide), [props.columns]); const lastHidableColumnIndex = useMemo(() => props.columns.map(c => c.canHide).lastIndexOf(true), [props.columns]); - useLayoutEffect(() => { - if (show) { - // Focus the first visible column - setTimeout(() => { - (refs.floating?.current?.querySelector("li") as HTMLElement)?.focus(); - }, 10); - } else { - // focus back to the button when closing (prevent scroll to prevent horizontal scroll jumps on initial render) - setTimeout(() => { - (refs.reference?.current as HTMLElement)?.focus({ preventScroll: true }); - }, 10); - } - }, [show]); - const optionsComponent = (
    - {show && optionsComponent} + {show && ( + + {optionsComponent} + + )} ); }