Repository: Sage/carbon (ts)

Issue:
`FlatTableRowHeader` with `Button` causes extra paddings
### Current behaviour

The default settings cause extra paddings within the cell,

```
      <FlatTableRowHeader stickyAlignment="right">
        <Button>Default</Button>
      </FlatTableRowHeader>
```

<img width="126" alt="Screenshot 2024-02-01 at 11 27 07" src="https://github.com/Sage/carbon/assets/90848080/a3fe3594-50b1-4eb7-a256-8a0a2c3d37f7">


With p={0} attribute, focus outline gets partially hidden
```
      <FlatTableRowHeader p={0} stickyAlignment="right">
        <Button>Padding 0</Button>
      </FlatTableRowHeader>
```
<img width="219" alt="Screenshot 2024-02-01 at 11 28 58" src="https://github.com/Sage/carbon/assets/90848080/1d583eee-4777-496a-a919-23a94bb8c60d">



### Expected behaviour

When a `Button` is placed within a sticky cell, it should not result in additional padding, and the focus outline should be fully visible.
<img width="168" alt="Screenshot 2024-02-01 at 11 29 45" src="https://github.com/Sage/carbon/assets/90848080/a3491425-c73f-4cb8-8801-a636adafae3f">



### CodeSandbox or Storybook URL

https://codesandbox.io/p/sandbox/table-padding-focus-kzm5nr

### JIRA Ticket (Sage Only)

SBS-81079

### Suggested Solution

_No response_

### Carbon Version

124.6.0

### Design Tokens Version

4.28.0

### What browsers are you seeing the problem on?

Chrome

### What Operating System are you seeing the problem on?

MacOS

### Anything else we should know?

_No response_

### Confidentiality

- [X] I confirm there is no confidential or commercially sensitive information included.

Pull request:
fix(flat-table): sticky column with button - focus border partially covered in expanded rows
fixes #6561

- The component `FlatTableRowHeader` uses `position: sticky;` and also recevies `p={0}`. 
- If the component `FlatTableRowHeader` receives the prop `stickyAlignment` with the value `left` any `FlatTableCell` to the left of the `FlatTableRowHeader` will also receive `position: sticky;`. 
- If the component `FlatTableRowHeader` receives the prop `stickyAlignment` with the value `right` any `FlatTableCell` to the right of the `FlatTableRowHeader` will also receive `position: sticky;`.
 
For each `FlatTableRowHeader` or `FlatTableCell` that are using `position: sticky;` together with z-index a new stacking context is created.

Because all the created stacking contexts have the same z-index value, they will render in the order in which they have been added into the hierarchy which means the element that appears later in the HTML will be rendered on top of the element that appears earlier, and we get the following scenario:

![1](https://github.com/Sage/carbon/assets/101639841/059ce8b7-22be-42b2-a173-d4be71456975)

The `th` element is under the `td` to the right and the `th` below it.

In order to fix this, we need to increase the z-index of the cell containing the button to be higher than the rest of the cells that are sticky.

![2](https://github.com/Sage/carbon/assets/101639841/ded1827a-9a4c-43c9-81d3-d7301492fd80)

This behavior can be observed in the test story `FlatRowHeaderWithNoPaddingAndButtons`

Patch:
diff --git a/src/components/flat-table/__internal__/use-table-cell.ts b/src/components/flat-table/__internal__/use-table-cell.ts
index 59dc5d50c..e81086c0b 100644
--- a/src/components/flat-table/__internal__/use-table-cell.ts
+++ b/src/components/flat-table/__internal__/use-table-cell.ts
@@ -24,6 +24,67 @@ export default (id: string) => {
   const isFirstCell = id === firstCellId;
   const isExpandableCell = expandable && isFirstCell && firstColumnExpandable;
 
+  const bringToFront = (
+    ev:
+      | React.MouseEvent<HTMLElement, MouseEvent>
+      | React.FocusEvent<HTMLElement>,
+    tagName: "TD" | "TH"
+  ) => {
+    /* istanbul ignore if */
+    if (
+      !ev ||
+      !ev.nativeEvent ||
+      typeof ev.nativeEvent.composedPath !== "function"
+    ) {
+      return;
+    }
+
+    const { nativeEvent } = ev;
+
+    // get the entire path of the event
+    const path = nativeEvent.composedPath();
+
+    // get the table from the path
+    const tableBody = path.find((el) => {
+      return el instanceof HTMLElement && el.tagName === "TBODY";
+    });
+
+    // if there is no table in the path we don't do anything
+    if (!tableBody) {
+      return;
+    }
+
+    // get all the th and td elements that are sticky
+    const stickyCells = Array.from(
+      (tableBody as HTMLElement).querySelectorAll("th, td")
+    ).filter((el) => {
+      return (
+        el.getAttribute("data-sticky-align") === "left" ||
+        el.getAttribute("data-sticky-align") === "right" ||
+        el.classList.contains("isSticky")
+      );
+    });
+
+    // reset the z-index to the default value for all the sticky cells, in case other cells were clicked before
+    stickyCells.map((el) => {
+      (el as HTMLElement).classList.remove("bringToFront");
+      return el;
+    });
+
+    // find the current cell in the path
+    const cell = path.find(
+      (el) => el instanceof HTMLElement && el.tagName === tagName
+    );
+
+    // if the current cell is sticky, increase the z-index value
+    const cellIndex = stickyCells.indexOf(cell as HTMLTableCellElement);
+    if (cellIndex !== -1) {
+      (stickyCells[cellIndex] as HTMLTableCellElement).classList.add(
+        "bringToFront"
+      );
+    }
+  };
+
   useEffect(() => {
     const tabstopTimer = setTimeout(() => {
       setTabIndex(isExpandableCell && getTabStopElementId() === id ? 0 : -1);
@@ -46,5 +107,6 @@ export default (id: string) => {
     tabIndex,
     isInHighlightedRow: highlighted,
     isInSelectedRow: selected,
+    bringToFront,
   };
 };
diff --git a/src/components/flat-table/flat-table-cell/flat-table-cell.component.tsx b/src/components/flat-table/flat-table-cell/flat-table-cell.component.tsx
index 9eeb87642..98c4f91c1 100644
--- a/src/components/flat-table/flat-table-cell/flat-table-cell.component.tsx
+++ b/src/components/flat-table/flat-table-cell/flat-table-cell.component.tsx
@@ -59,8 +59,13 @@ export const FlatTableCell = ({
     isInHighlightedRow,
     isInSelectedRow,
     tabIndex,
+    bringToFront,
   } = useTableCell(internalId.current);
 
+  const handleOnFocus = (ev: React.FocusEvent<HTMLElement>) => {
+    bringToFront(ev, "TD");
+  };
+
   return (
     <StyledFlatTableCell
       leftPosition={leftPosition}
@@ -82,6 +87,7 @@ export const FlatTableCell = ({
       data-highlighted={isInHighlightedRow && isExpandableCell}
       {...rest}
       id={internalId.current}
+      onFocus={handleOnFocus}
     >
       <StyledCellContent
         title={
diff --git a/src/components/flat-table/flat-table-row-header/flat-table-row-header.component.tsx b/src/components/flat-table/flat-table-row-header/flat-table-row-header.component.tsx
index 9565b3ce2..df7f85d80 100644
--- a/src/components/flat-table/flat-table-row-header/flat-table-row-header.component.tsx
+++ b/src/components/flat-table/flat-table-row-header/flat-table-row-header.component.tsx
@@ -65,6 +65,7 @@ export const FlatTableRowHeader = ({
     tabIndex,
     isInHighlightedRow,
     isInSelectedRow,
+    bringToFront,
   } = useTableCell(internalId.current);
 
   const handleOnClick = useCallback(
@@ -74,6 +75,10 @@ export const FlatTableRowHeader = ({
     [isExpandableCell, onClick]
   );
 
+  const handleOnFocus = (ev: React.FocusEvent<HTMLElement>) => {
+    bringToFront(ev, "TH");
+  };
+
   const handleOnKeyDown = useCallback(
     (ev: React.KeyboardEvent<HTMLElement>) => {
       if (isExpandableCell && onKeyDown) {
@@ -109,6 +114,7 @@ export const FlatTableRowHeader = ({
       data-highlighted={isInHighlightedRow && isExpandableCell}
       {...rest}
       id={internalId.current}
+      onFocus={handleOnFocus}
     >
       <StyledFlatTableRowHeaderContent
         title={
diff --git a/src/components/flat-table/flat-table-row-header/flat-table-row-header.spec.tsx b/src/components/flat-table/flat-table-row-header/flat-table-row-header.spec.tsx
index d822e6df7..35cd97b6b 100644
--- a/src/components/flat-table/flat-table-row-header/flat-table-row-header.spec.tsx
+++ b/src/components/flat-table/flat-table-row-header/flat-table-row-header.spec.tsx
@@ -1,6 +1,7 @@
 import React from "react";
 import { mount, ReactWrapper } from "enzyme";
 
+import { render as rtlRender, screen } from "@testing-library/react";
 import { StyledFlatTableRowHeader } from "./flat-table-row-header.style";
 import FlatTableRowHeader, {
   FlatTableRowHeaderProps,
@@ -11,6 +12,11 @@ import {
 } from "../../../__spec_helper__/__internal__/test-utils";
 import StyledIcon from "../../icon/icon.style";
 import FlatTableRowContext from "../flat-table-row/__internal__/flat-table-row.context";
+import FlatTable from "../flat-table.component";
+import FlatTableBody from "../flat-table-body/flat-table-body.component";
+import FlatTableRow from "../flat-table-row/flat-table-row.component";
+import FlatTableCell from "../flat-table-cell/flat-table-cell.component";
+import Button from "../../button/button.component";
 
 describe("FlatTableRowHeader", () => {
   testStyledSystemPadding(
@@ -321,6 +327,97 @@ describe("FlatTableRowHeader", () => {
         );
       }
     );
+
+    it("increases the z-index of the sticky TH or TD if content is focused and they are part of a FlatTableBody", () => {
+      rtlRender(
+        <FlatTable>
+          <FlatTableBody>
+            <FlatTableRow>
+              <FlatTableCell data-role="cell">
+                <Button>cell button</Button>
+              </FlatTableCell>
+              <FlatTableRowHeader
+                data-role="header-one"
+                stickyAlignment="left"
+                p={0}
+              >
+                <Button>header one button</Button>
+              </FlatTableRowHeader>
+              <FlatTableCell>text content</FlatTableCell>
+            </FlatTableRow>
+            <FlatTableRow>
+              <FlatTableCell>text content</FlatTableCell>
+              <FlatTableRowHeader
+                data-role="header-two"
+                stickyAlignment="left"
+                p={0}
+              >
+                <Button>header two button</Button>
+              </FlatTableRowHeader>
+              <FlatTableCell>text content</FlatTableCell>
+            </FlatTableRow>
+          </FlatTableBody>
+        </FlatTable>
+      );
+
+      const headerOne = screen.getByTestId("header-one");
+      const headerOneButton = screen.getByRole("button", {
+        name: "header one button",
+      });
+
+      const headerTwo = screen.getByTestId("header-two");
+      const headerTwoButton = screen.getByRole("button", {
+        name: "header two button",
+      });
+
+      const cell = screen.getByTestId("cell");
+      const cellButton = screen.getByRole("button", { name: "cell button" });
+
+      headerOneButton.focus();
+
+      expect(cell).not.toHaveClass("bringToFront");
+      expect(headerOne).toHaveClass("bringToFront");
+      expect(headerTwo).not.toHaveClass("bringToFront");
+
+      headerTwoButton.focus();
+
+      expect(cell).not.toHaveClass("bringToFront");
+      expect(headerOne).not.toHaveClass("bringToFront");
+      expect(headerTwo).toHaveClass("bringToFront");
+
+      cellButton.focus();
+
+      expect(cell).toHaveClass("bringToFront");
+      expect(headerOne).not.toHaveClass("bringToFront");
+      expect(headerTwo).not.toHaveClass("bringToFront");
+    });
+
+    it("does not increase the z-index of the sticky TH or TD if they are not part of a FlatTableBody", () => {
+      rtlRender(
+        <FlatTableRow>
+          <FlatTableCell data-role="cell">
+            <Button>cell button</Button>
+          </FlatTableCell>
+          <FlatTableRowHeader
+            data-role="header-one"
+            stickyAlignment="left"
+            p={0}
+          >
+            <Button>header one button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+        </FlatTableRow>
+      );
+
+      const headerOne = screen.getByTestId("header-one");
+      const headerOneButton = screen.getByRole("button", {
+        name: "header one button",
+      });
+
+      headerOneButton.focus();
+
+      expect(headerOne).not.toHaveClass("bringToFront");
+    });
   });
 
   describe.each([
diff --git a/src/components/flat-table/flat-table-row/flat-table-row.style.ts b/src/components/flat-table/flat-table-row/flat-table-row.style.ts
index 20839177b..25eb89642 100644
--- a/src/components/flat-table/flat-table-row/flat-table-row.style.ts
+++ b/src/components/flat-table/flat-table-row/flat-table-row.style.ts
@@ -26,10 +26,12 @@ const firstColumnOldFocusStyling = `
   outline-offset: -1px;
 `;
 
-const newFocusStyling = `
-  ${addFocusStyling(true)}
-  z-index: 1000;
-`;
+const newFocusStyling = (theme: ThemeObject) => {
+  return `
+    ${addFocusStyling(true)}
+    z-index: ${theme.zIndex.overlay + 5};
+  `;
+};
 
 const getLeftStickyStyling = (index: number, themeOptOut: boolean) =>
   index === 0 &&
@@ -266,7 +268,7 @@ const StyledFlatTableRow = styled.tr<StyledFlatTableRowProps>`
             top: 0;
             bottom: 0px;
             ${!theme.focusRedesignOptOut
-              ? newFocusStyling
+              ? newFocusStyling(theme)
               : /* istanbul ignore next */ oldFocusStyling}
             pointer-events: none;
           }
@@ -306,7 +308,7 @@ const StyledFlatTableRow = styled.tr<StyledFlatTableRowProps>`
                 border: none;
                 content: "";
                 height: ${rowHeight}px;
-                ${newFocusStyling}
+                ${newFocusStyling(theme)}
               }
             `}
           `}
@@ -357,7 +359,7 @@ const StyledFlatTableRow = styled.tr<StyledFlatTableRowProps>`
 
           :focus {
             ${!theme.focusRedesignOptOut
-              ? newFocusStyling
+              ? newFocusStyling(theme)
               : /* istanbul ignore next */ firstColumnOldFocusStyling}
           }
 
diff --git a/src/components/flat-table/flat-table.style.ts b/src/components/flat-table/flat-table.style.ts
index 966ef1247..eedf6f1bd 100644
--- a/src/components/flat-table/flat-table.style.ts
+++ b/src/components/flat-table/flat-table.style.ts
@@ -284,6 +284,14 @@ const StyledFlatTableWrapper = styled(StyledBox)<StyledFlatTableWrapperProps>`
     z-index: ${({ theme }) => theme.zIndex.overlay};
   }
 
+  tbody
+    ${StyledFlatTableRowHeader}.bringToFront,
+    ${StyledFlatTableCell}.bringToFront,
+    tbody
+    ${StyledFlatTableCheckbox}.bringToFront {
+    z-index: ${({ theme }) => theme.zIndex.overlay + 5};
+  }
+
   ${({ footer }) =>
     footer &&
     css`


Test patch:
diff --git a/src/components/flat-table/flat-table-test.stories.tsx b/src/components/flat-table/flat-table-test.stories.tsx
index 005d961d4..d0982607d 100644
--- a/src/components/flat-table/flat-table-test.stories.tsx
+++ b/src/components/flat-table/flat-table-test.stories.tsx
@@ -14,11 +14,14 @@ import {
   FlatTableRowHeaderProps,
   FlatTableCellProps,
 } from ".";
+import Button from "../../../src/components/button";
 import Box from "../../../src/components/box";
 import Link from "../../../src/components/link";
 import guid from "../../__internal__/utils/helpers/guid";
 import { FLAT_TABLE_THEMES } from "./flat-table.config";
 import { WithSortingHeaders } from "./flat-table.stories";
+import Textbox from "../textbox/textbox.component";
+import DateInput from "../date/date.component";
 
 export default {
   title: "Flat Table/Test",
@@ -28,6 +31,7 @@ export default {
     "SortableStory",
     "SubRowsAsAComponentStory",
     "FlatTableSizeFocus",
+    "FlatRowHeaderWithNoPaddingAndButtons",
   ],
   parameters: {
     info: { disable: true },
@@ -496,3 +500,182 @@ export const FlatTableSizeFocus = () => {
     </Box>
   );
 };
+
+export const FlatRowHeaderWithNoPaddingAndButtons = () => {
+  const SubRows = [
+    <FlatTableRow key="sub-row-1">
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableRowHeader p={0} stickyAlignment="left">
+        <Button>Button</Button>
+      </FlatTableRowHeader>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableCell>
+        <Textbox label="" labelInline labelAlign="right" />
+      </FlatTableCell>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableRowHeader p={0} stickyAlignment="right">
+        subrow content
+      </FlatTableRowHeader>
+      <FlatTableCell>subrow content</FlatTableCell>
+    </FlatTableRow>,
+    <FlatTableRow key="sub-row-2">
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableRowHeader p={0} stickyAlignment="left">
+        subrow content
+      </FlatTableRowHeader>
+      <FlatTableCell>
+        <Button>Button</Button>
+      </FlatTableCell>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableCell>
+        <Textbox label="" labelInline labelAlign="right" />
+      </FlatTableCell>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableCell>subrow content</FlatTableCell>
+      <FlatTableRowHeader p={0} stickyAlignment="right">
+        subrow content
+      </FlatTableRowHeader>
+      <FlatTableCell>subrow content</FlatTableCell>
+    </FlatTableRow>,
+  ];
+  return (
+    <FlatTable width="800px" overflowX="auto">
+      <FlatTableHead>
+        <FlatTableRow>
+          <FlatTableHeader>Sticky TD</FlatTableHeader>
+          <FlatTableRowHeader p={0} stickyAlignment="left">
+            Sticky TH
+          </FlatTableRowHeader>
+          <FlatTableHeader>Column</FlatTableHeader>
+          <FlatTableHeader>Column</FlatTableHeader>
+          <FlatTableHeader>Column</FlatTableHeader>
+          <FlatTableHeader>Column</FlatTableHeader>
+          <FlatTableHeader>Column</FlatTableHeader>
+          <FlatTableHeader>Column</FlatTableHeader>
+          <FlatTableRowHeader p={0} stickyAlignment="right">
+            Sticky TH
+          </FlatTableRowHeader>
+          <FlatTableHeader>Sticky TD</FlatTableHeader>
+        </FlatTableRow>
+      </FlatTableHead>
+      <FlatTableBody>
+        <FlatTableRow>
+          <FlatTableCell>
+            <Textbox label="" labelInline labelAlign="right" />
+          </FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="left">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content </FlatTableCell>
+          <FlatTableCell>text content </FlatTableCell>
+          <FlatTableCell>text content </FlatTableCell>
+          <FlatTableCell>text content </FlatTableCell>
+          <FlatTableCell>text content </FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="right">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+        </FlatTableRow>
+        <FlatTableRow>
+          <FlatTableCell>
+            <DateInput
+              error=""
+              fieldHelp=""
+              helpAriaLabel=""
+              inputWidth={70}
+              label=""
+              labelHelp=""
+              labelWidth={30}
+              maxDate=""
+              minDate=""
+              mt={0}
+              name="dateinput"
+              onBlur={() => {}}
+              onChange={() => {}}
+              onClick={() => {}}
+              onKeyDown={() => {}}
+              prefix=""
+              size="medium"
+              value="2019-04-04"
+              warning=""
+            />
+          </FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="left">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>
+            <Textbox label="" labelInline labelAlign="right" />
+          </FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="right">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>
+            <Button>Button</Button>
+          </FlatTableCell>
+        </FlatTableRow>
+        <FlatTableRow>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="left">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>
+            <Textbox label="" labelInline labelAlign="right" />
+          </FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>
+            <Textbox label="" labelInline labelAlign="right" />
+          </FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="right">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+        </FlatTableRow>
+        <FlatTableRow expandable subRows={SubRows}>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="left">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="right">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+        </FlatTableRow>
+        <FlatTableRow expandable subRows={SubRows}>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="left">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableCell>text content</FlatTableCell>
+          <FlatTableRowHeader p={0} stickyAlignment="right">
+            <Button>Button</Button>
+          </FlatTableRowHeader>
+          <FlatTableCell>text content</FlatTableCell>
+        </FlatTableRow>
+      </FlatTableBody>
+    </FlatTable>
+  );
+};