diff --git a/packages/main/cypress/specs/TableNavigationFixedHeader.cy.tsx b/packages/main/cypress/specs/TableNavigationFixedHeader.cy.tsx
new file mode 100644
index 000000000000..da18e0fee502
--- /dev/null
+++ b/packages/main/cypress/specs/TableNavigationFixedHeader.cy.tsx
@@ -0,0 +1,199 @@
+import Table from "../../src/Table.js";
+import TableHeaderRow from "../../src/TableHeaderRow.js";
+import TableHeaderCell from "../../src/TableHeaderCell.js";
+import TableRow from "../../src/TableRow.js";
+import TableCell from "../../src/TableCell.js";
+import Label from "../../src/Label.js";
+import Bar from "../../src/Bar.js";
+import Title from "../../src/Title.js";
+import Slider from "../../src/Slider.js";
+
+describe("Table - Keyboard Navigation with Fixed Headers", () => {
+ function isDisplayedInsideViewport(element: string) {
+ cy.get(element).then($el => {
+ const el = $el[0];
+ const rect = el.getBoundingClientRect();
+
+ expect(rect.top).to.be.at.least(0);
+ expect(rect.left).to.be.at.least(0);
+ expect(rect.bottom).to.be.lessThan(Cypress.config("viewportHeight"));
+ expect(rect.right).to.be.lessThan(Cypress.config("viewportWidth"));
+ });
+ }
+
+ it("scrollable container - focused row should always be below the header", () => {
+ cy.mount(
+
+
+ My Selectable Products (3)
+
+
+
+
+ ColumnA
+ Column B
+ Column C
+ Column D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+
+ );
+
+ cy.get("#table0").children("ui5-table-row").as("rows");
+ cy.get("#table0").children("ui5-table-header-row").as("headerRow");
+ cy.get("@rows").get("#row-21").as("lastRow");
+
+ cy.get("@lastRow").scrollIntoView();
+ cy.get("@lastRow").click("left");
+ cy.get("@lastRow").should("be.focused");
+
+ for (let i = 20; i > 0; i--) {
+ cy.realPress("{uparrow}");
+ cy.get("@rows").get(`#row-${i}`).should("be.focused");
+
+ isDisplayedInsideViewport("@headerRow");
+
+ cy.get("@headerRow").then($headerRow => {
+ cy.get("@rows").get(`#row-${i}`).then($row => {
+ const headerRowBottom = $headerRow[0].getBoundingClientRect().bottom;
+ const focusedRowTop = $row[0].getBoundingClientRect().top;
+
+ expect(focusedRowTop).to.be.at.least(headerRowBottom);
+ });
+ });
+ }
+ });
+
+ it("scrollable table - focused row should always be below the header", () => {
+ cy.mount(
+
+
+ ColumnA
+ Column B
+ Column C
+ Column D
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+
+ );
+
+ cy.get("#table1").children("ui5-table-row").as("rows");
+ cy.get("#table1").children("ui5-table-header-row").as("headerRow");
+ cy.get("@rows").get("#row-21-1").as("lastRow");
+
+ cy.get("@lastRow").scrollIntoView();
+ cy.get("@lastRow").click("left");
+ cy.get("@lastRow").should("be.focused");
+
+ for (let i = 20; i > 0; i--) {
+ cy.realPress("{uparrow}");
+ cy.get("@rows").get(`#row-${i}-1`).should("be.focused");
+
+ isDisplayedInsideViewport("@headerRow");
+
+ cy.get("@headerRow").then($headerRow => {
+ cy.get("@rows").get(`#row-${i}-1`).then($row => {
+ const headerRowBottom = $headerRow[0].getBoundingClientRect().bottom;
+ const focusedRowTop = $row[0].getBoundingClientRect().top;
+
+ expect(focusedRowTop).to.be.at.least(headerRowBottom);
+ });
+ });
+ }
+ });
+
+ it("body as scroll container - focused row should always be below the header", () => {
+ cy.mount(
+ <>
+
+ My Selectable Products (3)
+
+
+
+
+ ColumnA
+ Column B
+ Column C
+ Column D
+
+ ${Array.from({ length: 100 }).map((row, index) =>
+
+
+
+
+
+
+
+ )}
+
+ >
+ );
+
+ cy.get("#table2").children("ui5-table-row").as("rows");
+ cy.get("#table2").children("ui5-table-header-row").as("headerRow");
+ cy.get("@rows").get("#row-100-2").as("lastRow");
+
+ cy.get("@lastRow").scrollIntoView();
+ cy.get("@lastRow").click("left");
+ cy.get("@lastRow").should("be.focused");
+
+ for (let i = 99; i > 0; i--) {
+ cy.realPress("{uparrow}");
+ cy.get("@rows").get(`#row-${i}-2`).should("be.focused");
+
+ isDisplayedInsideViewport("@headerRow");
+
+ cy.get("@headerRow").then($headerRow => {
+ cy.get("@rows").get(`#row-${i}-2`).then($row => {
+ const headerRowBottom = $headerRow[0].getBoundingClientRect().bottom;
+ const focusedRowTop = $row[0].getBoundingClientRect().top;
+
+ expect(focusedRowTop).to.be.at.least(headerRowBottom);
+ });
+ });
+ }
+ });
+});