Repository: Sage/carbon (ts)

Issue:
[Popover Container] VoiceOver issue when popover-container-content is opening at the end of node tree.
### Description

Hi, Im using a Form as content in Popover container component. By moving though it using Voice Over (MacOs accessibility tool) by using its keys (Find more here https://dequeuniversity.com/screenreaders/voiceover-keyboard-shortcuts) I cannot reach the rendered "popover-container-content" in order as its being rendered at the end of the dom tree besides being rendered aside its trigger component like its button. 

### Reproduction

https://stackblitz.com/edit/parsium-carbon-starter-4r7bjmew?file=package.json

### Steps to reproduce

Open StackBlitz example
Turn on VoiceOver 
Use VO keys and move into the preview
Open the contextual menu (popover) using VO + SpaceBar
Try to move inside the popover to further access their form fields by using VO + Right arrow
There the issue reproduces, you cannot reach the popover and you move further to the next buttons

### JIRA ticket numbers (Sage only)

SBS-117650

### Suggested solution

I remember some `disable-portal` feature that was used previously for these same reasons, do you plan something similar? 
What I can suggest is to bring something like that back.

By tabbing this works ok in browsers but we are trying to bring support to Voice Over and assistive tehcnologies so the interaction is made with different controls that are being affected by this rendering order.

Thanks!

### Carbon version

144.22.1

### Design tokens version

4.34.0

### Relevant browsers

Chrome, Safari

### Relevant OSs

MacOS

### Additional context

_No response_

### Confidentiality

- [X] I confirm there is no confidential or commercially sensitive information included.

Pull request:
fix(popover-container): ensure component is accessible by screen readers
fix #7133 

### Proposed behaviour

<!--
A clear and concise description of what changes this PR makes. If applicable, include any UI screenshots to help explain your request. If you are a Sage contributor, please DO NOT share any commercially sensitive information, such as UI screenshots or code from Sage products.
-->

- The popover dialog gains focus when opened to allow screen readers to access the popup. 
- Adds `hasFullWidth` prop to enable fullWidth Button behaviour optionally. 
- Expose `focusButton` method to enable consumers to programatically focus the open button.
- Ensure Form within a PopoverContainer had expected overflow styling and stickyFooter has correct border-radius. 

![image](https://github.com/user-attachments/assets/4e6b7f56-54ce-45a8-8e06-1e88a66c96b2)

### Current behaviour

<!--
A clear and concise description of the behaviour before this change. If applicable, include any UI screenshots to help explain your request. If you are a Sage contributor, please DO NOT share any commercially sensitive information, such as UI screenshots or code from Sage products.
-->
- The component renders in a Portal and cannot be accessed by screen reader commands. 
- Component has 100% width causing other elements to render below it. 
- Form within a PopoverContainer does not have overflow styling. 

![image](https://github.com/user-attachments/assets/facb997c-4223-4a1b-b7ef-8e389063881a)

### Checklist

<!-- Each PR should include the following -->

- [x] Commits follow our style guide
- [x] Related issues linked in commit messages if required
- [x] Screenshots are included in the PR if useful
- [ ] All themes are supported if required
- [x] Unit tests added or updated if required
- [ ] Playwright automation tests added or updated if required
- [x] Storybook added or updated if required
- [ ] Translations added or updated (including creating or amending translation keys table in storybook) if required
- [ ] Typescript `d.ts` file added or updated if required
- [ ] Related docs have been updated if required

#### QA

- [ ] Tested in provided StackBlitz sandbox/Storybook
- [ ] Add new Playwright test coverage if required
- [ ] Carbon implementation matches Design System/designs
- [ ] UI Tests GitHub check reviewed if required

### Additional context

<!-- Add any other context or links about the pull request here. -->

### Testing instructions

<!--
How can a reviewer test this PR?

If this PR addresses a pre-existing bug, please include a link to a sandbox that reproduces the original bug. A starter template has been provided to help you do this:
<https://stackblitz.com/fork/github/Parsium/carbon-starter>
-->


Patch:
diff --git a/src/components/popover-container/index.ts b/src/components/popover-container/index.ts
index 306cb833c..01537fc6b 100644
--- a/src/components/popover-container/index.ts
+++ b/src/components/popover-container/index.ts
@@ -3,4 +3,5 @@ export type {
   PopoverContainerProps,
   RenderCloseProps,
   RenderOpenProps,
+  PopoverContainerHandle,
 } from "./popover-container.component";
diff --git a/src/components/popover-container/popover-container.component.tsx b/src/components/popover-container/popover-container.component.tsx
index 5d707157d..f77546222 100644
--- a/src/components/popover-container/popover-container.component.tsx
+++ b/src/components/popover-container/popover-container.component.tsx
@@ -4,6 +4,8 @@ import React, {
   useRef,
   useState,
   useMemo,
+  useImperativeHandle,
+  forwardRef,
 } from "react";
 import { PaddingProps } from "styled-system";
 import { CSSTransition } from "react-transition-group";
@@ -151,8 +153,14 @@ export interface PopoverContainerProps extends PaddingProps {
   containerAriaLabel?: string;
   /** Disables the animation for the component */
   disableAnimation?: boolean;
+  /** Flag to enable fullWidth Button styles */
+  hasFullWidth?: boolean;
 }
 
+export type PopoverContainerHandle = {
+  focusButton: () => void;
+} | null;
+
 function usePopoverMiddleware(shouldCoverButton: boolean) {
   return useMemo(
     () => [
@@ -169,262 +177,291 @@ function usePopoverMiddleware(shouldCoverButton: boolean) {
   );
 }
 
-export const PopoverContainer = ({
-  children,
-  title,
-  position = "right",
-  open,
-  onOpen,
-  onClose,
-  renderOpenComponent = renderOpen,
-  renderCloseComponent = renderClose,
-  shouldCoverButton = false,
-  ariaDescribedBy,
-  openButtonAriaLabel,
-  closeButtonAriaLabel = "close",
-  containerAriaLabel,
-  closeButtonDataProps,
-  disableAnimation = false,
-  ...rest
-}: PopoverContainerProps) => {
-  const isControlled = open !== undefined;
-  const [isOpenInternal, setIsOpenInternal] = useState(false);
-
-  const closeButtonRef = useRef<HTMLButtonElement>(null);
-  const openButtonRef = useRef<HTMLButtonElement>(null);
-  const popoverReference = useRef<HTMLDivElement>(null);
-  const guid = useRef(createGuid());
-  const popoverContentNodeRef = useRef<HTMLDivElement>(null);
-  const popoverContainerId = title
-    ? `PopoverContainer_${guid.current}`
-    : undefined;
-
-  const isOpen = isControlled ? open : isOpenInternal;
-
-  const reduceMotion = !useMediaQuery(
-    "screen and (prefers-reduced-motion: no-preference)",
-  );
+export const PopoverContainer = forwardRef<
+  PopoverContainerHandle,
+  PopoverContainerProps
+>(
+  (
+    {
+      children,
+      title,
+      position = "right",
+      open,
+      onOpen,
+      onClose,
+      renderOpenComponent = renderOpen,
+      renderCloseComponent = renderClose,
+      shouldCoverButton = false,
+      ariaDescribedBy,
+      openButtonAriaLabel,
+      closeButtonAriaLabel = "close",
+      containerAriaLabel,
+      closeButtonDataProps,
+      disableAnimation = false,
+      hasFullWidth = false,
+      ...rest
+    },
+    ref,
+  ) => {
+    const isControlled = open !== undefined;
+    const [isOpenInternal, setIsOpenInternal] = useState(false);
+
+    const closeButtonRef = useRef<HTMLButtonElement>(null);
+    const openButtonRef = useRef<HTMLButtonElement>(null);
+    const popoverReference = useRef<HTMLDivElement>(null);
+    const guid = useRef(createGuid());
+    const popoverContentNodeRef = useRef<HTMLDivElement>(null);
+    const popoverContainerId = title
+      ? `PopoverContainer_${guid.current}`
+      : undefined;
+
+    const isOpen = isControlled ? open : isOpenInternal;
+
+    const reduceMotion = !useMediaQuery(
+      "screen and (prefers-reduced-motion: no-preference)",
+    );
 
-  const popoverMiddleware = usePopoverMiddleware(shouldCoverButton);
+    const popoverMiddleware = usePopoverMiddleware(shouldCoverButton);
 
-  const closePopover = useCallback(
-    (
-      ev:
-        | React.MouseEvent<HTMLElement>
-        | React.KeyboardEvent<HTMLElement>
-        | KeyboardEvent,
-    ) => {
-      /* istanbul ignore else */
-      if (!isControlled) setIsOpenInternal(false);
+    const closePopover = useCallback(
+      (
+        ev:
+          | React.MouseEvent<HTMLElement>
+          | React.KeyboardEvent<HTMLElement>
+          | KeyboardEvent,
+      ) => {
+        /* istanbul ignore else */
+        if (!isControlled) setIsOpenInternal(false);
 
-      onClose?.(ev);
+        onClose?.(ev);
 
-      /* istanbul ignore else */
-      if (isOpen) openButtonRef.current?.focus();
-    },
-    [isControlled, isOpen, onClose],
-  );
+        /* istanbul ignore else */
+        if (isOpen) openButtonRef.current?.focus();
+      },
+      [isControlled, isOpen, onClose],
+    );
 
-  const handleEscKey = useCallback(
-    (ev) => {
-      const eventIsFromSelectInput = Events.composedPath(ev).find((element) => {
-        return (
-          element instanceof HTMLElement &&
-          element.getAttribute("data-element") === "input" &&
-          element.getAttribute("aria-expanded") === "true"
+    const handleEscKey = useCallback(
+      (ev) => {
+        const eventIsFromSelectInput = Events.composedPath(ev).find(
+          (element) => {
+            return (
+              element instanceof HTMLElement &&
+              element.getAttribute("data-element") === "input" &&
+              element.getAttribute("aria-expanded") === "true"
+            );
+          },
         );
-      });
 
-      if (!eventIsFromSelectInput && Events.isEscKey(ev)) {
-        closePopover(ev);
+        if (!eventIsFromSelectInput && Events.isEscKey(ev)) {
+          closePopover(ev);
+        }
+      },
+      [closePopover],
+    );
+
+    useEffect(() => {
+      document.addEventListener("keydown", handleEscKey);
+
+      return () => {
+        document.removeEventListener("keydown", handleEscKey);
+      };
+    }, [handleEscKey]);
+
+    useEffect(() => {
+      if (!shouldCoverButton && isOpen) {
+        popoverContentNodeRef.current?.focus({ preventScroll: true });
       }
-    },
-    [closePopover],
-  );
+    }, [isOpen, shouldCoverButton, popoverContentNodeRef]);
 
-  useEffect(() => {
-    document.addEventListener("keydown", handleEscKey);
+    const handleOpenButtonClick = (
+      e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
+    ) => {
+      /* istanbul ignore else */
+      if (!isControlled) setIsOpenInternal(!isOpen);
 
-    return () => {
-      document.removeEventListener("keydown", handleEscKey);
+      // We want the open button to close the popover if it is already open
+      if (!isOpen) onOpen?.(e);
+      else onClose?.(e);
     };
-  }, [handleEscKey]);
 
-  const handleOpenButtonClick = (
-    e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
-  ) => {
-    /* istanbul ignore else */
-    if (!isControlled) setIsOpenInternal(!isOpen);
+    const handleCloseButtonClick = (
+      e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
+    ) => {
+      closePopover(e);
+    };
 
-    // We want the open button to close the popover if it is already open
-    if (!isOpen) onOpen?.(e);
-    else onClose?.(e);
-  };
+    useFocusPortalContent(
+      shouldCoverButton ? undefined : popoverContentNodeRef,
+      shouldCoverButton ? undefined : openButtonRef,
+      closePopover,
+    );
 
-  const handleCloseButtonClick = (
-    e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLElement>,
-  ) => {
-    closePopover(e);
-  };
+    const onFocusNextElement = useCallback((ev) => {
+      const allFocusableElements: HTMLElement[] = Array.from(
+        document.querySelectorAll(defaultFocusableSelectors) ||
+          /* istanbul ignore next */ [],
+      );
+      const filteredElements = allFocusableElements.filter(
+        (el) => el === openButtonRef.current || Number(el.tabIndex) !== -1,
+      );
+
+      const openButtonRefIndex = filteredElements.indexOf(
+        openButtonRef.current as HTMLElement,
+      );
+
+      filteredElements[openButtonRefIndex + 1].focus();
+      closePopover(ev);
+      // eslint-disable-next-line react-hooks/exhaustive-deps
+    }, []);
+
+    const handleFocusGuard = (
+      direction: "prev" | "next",
+      ev: React.FocusEvent<HTMLElement>,
+    ) => {
+      if (direction === "next" && onFocusNextElement) {
+        // Focus the next focusable element outside of the popover
+        onFocusNextElement(ev);
+        return;
+      }
 
-  useFocusPortalContent(
-    shouldCoverButton ? undefined : popoverContentNodeRef,
-    shouldCoverButton ? undefined : openButtonRef,
-    closePopover,
-  );
+      // istanbul ignore else
+      if (direction === "prev") openButtonRef.current?.focus();
+    };
 
-  const onFocusNextElement = useCallback((ev) => {
-    const allFocusableElements: HTMLElement[] = Array.from(
-      document.querySelectorAll(defaultFocusableSelectors) ||
-        /* istanbul ignore next */ [],
-    );
-    const filteredElements = allFocusableElements.filter(
-      (el) => el === openButtonRef.current || Number(el.tabIndex) !== -1,
-    );
+    const renderOpenComponentProps = {
+      tabIndex: 0,
+      "aria-expanded": isOpen,
+      "aria-haspopup": "dialog" as const,
+      isOpen,
+      "data-element": "popover-container-open-component",
+      onClick: handleOpenButtonClick,
+      ref: openButtonRef,
+      "aria-label": openButtonAriaLabel || title,
+      id: isOpen ? undefined : popoverContainerId,
+    };
 
-    const openButtonRefIndex = filteredElements.indexOf(
-      openButtonRef.current as HTMLElement,
-    );
+    const renderCloseComponentProps = {
+      "data-element": "popover-container-close-component",
+      tabIndex: 0,
+      onClick: handleCloseButtonClick,
+      ref: closeButtonRef,
+      "aria-label": closeButtonAriaLabel,
+      closeButtonDataProps,
+    };
 
-    filteredElements[openButtonRefIndex + 1].focus();
-    closePopover(ev);
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, []);
+    const handleClickAway = (e: Event) => {
+      if (!isControlled) setIsOpenInternal(false);
+      if (isOpen) onClose?.(e);
+    };
 
-  const handleFocusGuard = (
-    direction: "prev" | "next",
-    ev: React.FocusEvent<HTMLElement>,
-  ) => {
-    if (direction === "next" && onFocusNextElement) {
-      // Focus the next focusable element outside of the popover
-      onFocusNextElement(ev);
-      return;
-    }
-
-    // istanbul ignore else
-    if (direction === "prev") openButtonRef.current?.focus();
-  };
-
-  const renderOpenComponentProps = {
-    tabIndex: 0,
-    "aria-expanded": isOpen,
-    "aria-haspopup": "dialog" as const,
-    isOpen,
-    "data-element": "popover-container-open-component",
-    onClick: handleOpenButtonClick,
-    ref: openButtonRef,
-    "aria-label": openButtonAriaLabel || title,
-    id: isOpen ? undefined : popoverContainerId,
-  };
-
-  const renderCloseComponentProps = {
-    "data-element": "popover-container-close-component",
-    tabIndex: 0,
-    onClick: handleCloseButtonClick,
-    ref: closeButtonRef,
-    "aria-label": closeButtonAriaLabel,
-    closeButtonDataProps,
-  };
-
-  const handleClickAway = (e: Event) => {
-    if (!isControlled) setIsOpenInternal(false);
-    if (isOpen) onClose?.(e);
-  };
-
-  const handleClick = useClickAwayListener(handleClickAway, "mousedown");
-  const [isAnimationComplete, setIsAnimationComplete] = useState(false);
-
-  const popover = () => (
-    <PopoverContainerContentStyle
-      data-element="popover-container-content"
-      role="dialog"
-      aria-labelledby={popoverContainerId}
-      aria-label={containerAriaLabel}
-      aria-describedby={ariaDescribedBy}
-      p="16px 24px"
-      ref={popoverContentNodeRef}
-      tabIndex={shouldCoverButton ? -1 : undefined}
-      disableAnimation={disableAnimation || reduceMotion}
-      {...filterStyledSystemPaddingProps(rest)}
-    >
-      <PopoverContainerHeaderStyle>
-        <PopoverContainerTitleStyle
-          id={popoverContainerId}
-          data-element="popover-container-title"
-        >
-          {title}
-        </PopoverContainerTitleStyle>
-        {renderCloseComponent(renderCloseComponentProps)}
-      </PopoverContainerHeaderStyle>
-      {children}
-    </PopoverContainerContentStyle>
-  );
+    const handleClick = useClickAwayListener(handleClickAway, "mousedown");
+    const [isAnimationComplete, setIsAnimationComplete] = useState(false);
 
-  const childrenToRender = () =>
-    shouldCoverButton ? (
-      <ModalContext.Provider value={{ isAnimationComplete }}>
-        <FocusTrap wrapperRef={popoverContentNodeRef} isOpen={isOpen}>
-          {popover()}
-        </FocusTrap>
-      </ModalContext.Provider>
-    ) : (
-      <>
-        <div
-          data-element="tab-guard-top"
-          // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
-          tabIndex={0}
-          aria-hidden
-          onFocus={(ev) => handleFocusGuard("prev", ev)}
-        />
-        {popover()}
-        <div
-          data-element="tab-guard-bottom"
-          // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
-          tabIndex={0}
-          aria-hidden
-          onFocus={(ev) => handleFocusGuard("next", ev)}
-        />
-      </>
+    useImperativeHandle<PopoverContainerHandle, PopoverContainerHandle>(
+      ref,
+      () => ({
+        focusButton() {
+          openButtonRef.current?.focus();
+        },
+      }),
+      [],
     );
 
-  return (
-    <PopoverContainerWrapperStyle
-      data-component="popover-container"
-      onMouseDown={handleClick}
-    >
-      <div ref={popoverReference}>
-        {renderOpenComponent(renderOpenComponentProps)}
-      </div>
-      <CSSTransition
-        nodeRef={popoverContentNodeRef}
-        timeout={{ exit: disableAnimation ? 0 : 300 }}
-        in={isOpen}
-        unmountOnExit
-        onEntered={
-          shouldCoverButton
-            ? /* istanbul ignore next */ () => setIsAnimationComplete(true)
-            : undefined
-        }
-        onExiting={
-          shouldCoverButton
-            ? /* istanbul ignore next */ () => setIsAnimationComplete(false)
-            : undefined
-        }
+    const popover = () => (
+      <PopoverContainerContentStyle
+        data-element="popover-container-content"
+        role="dialog"
+        aria-labelledby={popoverContainerId}
+        aria-label={containerAriaLabel}
+        aria-describedby={ariaDescribedBy}
+        p="16px 24px"
+        ref={popoverContentNodeRef}
+        tabIndex={-1}
+        disableAnimation={disableAnimation || reduceMotion}
+        {...filterStyledSystemPaddingProps(rest)}
+      >
+        <PopoverContainerHeaderStyle>
+          <PopoverContainerTitleStyle
+            id={popoverContainerId}
+            data-element="popover-container-title"
+          >
+            {title}
+          </PopoverContainerTitleStyle>
+          {renderCloseComponent(renderCloseComponentProps)}
+        </PopoverContainerHeaderStyle>
+        {children}
+      </PopoverContainerContentStyle>
+    );
+
+    const childrenToRender = () =>
+      shouldCoverButton ? (
+        <ModalContext.Provider value={{ isAnimationComplete }}>
+          <FocusTrap wrapperRef={popoverContentNodeRef} isOpen={isOpen}>
+            {popover()}
+          </FocusTrap>
+        </ModalContext.Provider>
+      ) : (
+        <>
+          <div
+            data-element="tab-guard-top"
+            // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
+            tabIndex={0}
+            aria-hidden
+            onFocus={(ev) => handleFocusGuard("prev", ev)}
+          />
+          {popover()}
+          <div
+            data-element="tab-guard-bottom"
+            // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
+            tabIndex={0}
+            aria-hidden
+            onFocus={(ev) => handleFocusGuard("next", ev)}
+          />
+        </>
+      );
+
+    return (
+      <PopoverContainerWrapperStyle
+        data-component="popover-container"
+        data-role="popover-container"
+        onMouseDown={handleClick}
+        hasFullWidth={hasFullWidth}
       >
-        <Popover
-          reference={popoverReference}
-          placement={position === "right" ? "bottom-start" : "bottom-end"}
-          popoverStrategy={
-            disableAnimation || reduceMotion ? "fixed" : "absolute"
+        <div ref={popoverReference}>
+          {renderOpenComponent(renderOpenComponentProps)}
+        </div>
+        <CSSTransition
+          nodeRef={popoverContentNodeRef}
+          timeout={{ exit: disableAnimation ? 0 : 300 }}
+          in={isOpen}
+          unmountOnExit
+          onEntered={
+            shouldCoverButton
+              ? /* istanbul ignore next */ () => setIsAnimationComplete(true)
+              : undefined
+          }
+          onExiting={
+            shouldCoverButton
+              ? /* istanbul ignore next */ () => setIsAnimationComplete(false)
+              : undefined
           }
-          middleware={popoverMiddleware}
-          childRefOverride={popoverContentNodeRef}
         >
-          {childrenToRender()}
-        </Popover>
-      </CSSTransition>
-    </PopoverContainerWrapperStyle>
-  );
-};
+          <Popover
+            reference={popoverReference}
+            placement={position === "right" ? "bottom-start" : "bottom-end"}
+            popoverStrategy={
+              disableAnimation || reduceMotion ? "fixed" : "absolute"
+            }
+            middleware={popoverMiddleware}
+            childRefOverride={popoverContentNodeRef}
+          >
+            {childrenToRender()}
+          </Popover>
+        </CSSTransition>
+      </PopoverContainerWrapperStyle>
+    );
+  },
+);
 
 export default PopoverContainer;
diff --git a/src/components/popover-container/popover-container.mdx b/src/components/popover-container/popover-container.mdx
index 4b81fc1e7..4be2ea7cb 100644
--- a/src/components/popover-container/popover-container.mdx
+++ b/src/components/popover-container/popover-container.mdx
@@ -86,7 +86,7 @@ You can easily use many different components to create your own composition.
 ### Filter component
 
 If you want to use the `PopoverContainer` to create for example `Filter` component.
-You can do it easly in this way:
+You can do it easily in this way:
 
 **Please note you should supply an `onClose` when controlling the `open` state in order for the `PopoverContainer` to close when clicking outside of the wrapper element**
 
@@ -98,6 +98,15 @@ It is possible to disable the animations applied to the `PopoverContainer` by se
 
 <Canvas of={PopoverContainerStories.DisableAnimation} />
 
+### Focusing the open button programmatically
+
+The component exposes a `focusButton` function that supports programmatically focusing on the open button, which can be called by passing a ref to the `PopoverContainer` component.
+This can be useful when closing or submitting a Form within `PopoverContainer`.
+
+**Please note you should supply an `onClose` when controlling the `open` state in order for the `PopoverContainer` to close when clicking outside of the wrapper element**
+
+<Canvas of={PopoverContainerStories.FocusButton} />
+
 ## Props
 
 ### Popover Container
diff --git a/src/components/popover-container/popover-container.stories.tsx b/src/components/popover-container/popover-container.stories.tsx
index 1edfa75cf..1470b5a66 100644
--- a/src/components/popover-container/popover-container.stories.tsx
+++ b/src/components/popover-container/popover-container.stories.tsx
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React, { useState, useRef } from "react";
 import { Meta, StoryObj } from "@storybook/react";
 
 import generateStyledSystemProps from "../../../.storybook/utils/styled-system-props";
@@ -12,25 +12,45 @@ import Pill from "../pill";
 import Badge from "../badge";
 import isChromatic from "../../../.storybook/isChromatic";
 import { Select, Option } from "../select";
-import PopoverContainer from "./popover-container.component";
+import PopoverContainer, {
+  PopoverContainerHandle,
+} from "./popover-container.component";
+import Textbox from "../textbox";
+import Form from "../form";
 
 const styledSystemProps = generateStyledSystemProps({
   padding: true,
 });
 
+const defaultOpenState = isChromatic();
+
 const meta: Meta<typeof PopoverContainer> = {
   title: "Popover Container",
   component: PopoverContainer,
   argTypes: {
     ...styledSystemProps,
   },
+  parameters: {
+    themeProvider: { chromatic: { theme: "sage" } },
+  },
+  decorators: [
+    (Story) => (
+      <>
+        {defaultOpenState ? (
+          <Box width="100vw" height="100vh">
+            <Story />
+          </Box>
+        ) : (
+          <Story />
+        )}
+      </>
+    ),
+  ],
 };
 
 export default meta;
 type Story = StoryObj<typeof PopoverContainer>;
 
-const defaultOpenState = isChromatic();
-
 export const Default: Story = () => {
   return (
     <Box height={100}>
@@ -243,7 +263,7 @@ export const Filter: Story = () => {
     { value: "Option 2", checked: false },
     { value: "Option 3", checked: false },
   ];
-  const [open, setOpen] = useState(false);
+  const [open, setOpen] = useState(defaultOpenState);
   const [options, setOptions] = useState<OptionsType[]>(initValues);
   const [filters, setFilters] = useState<OptionsType[]>([]);
   const clearAllOptions = () => {
@@ -355,3 +375,57 @@ export const DisableAnimation: Story = () => {
   );
 };
 DisableAnimation.storyName = "Disable Animation";
+
+export const FocusButton = () => {
+  const [isPopOverOpen, setIsPopOverOpen] = useState(defaultOpenState);
+  const ref = useRef<PopoverContainerHandle>(null);
+
+  const handleCancel = () => {
+    setIsPopOverOpen(false);
+    ref.current?.focusButton();
+  };
+
+  return (
+    <PopoverContainer
+      p={0}
+      ref={ref}
+      containerAriaLabel="popover with form"
+      open={isPopOverOpen}
+      onOpen={() => setIsPopOverOpen(true)}
+      onClose={() => setIsPopOverOpen(false)}
+      renderOpenComponent={({ ...props }) => (
+        <Button
+          size="small"
+          buttonType="secondary"
+          iconType="settings"
+          {...props}
+        >
+          popover
+        </Button>
+      )}
+      renderCloseComponent={() => <></>}
+    >
+      <Form
+        height="400px"
+        onSubmit={() => {}}
+        leftSideButtons={<Button onClick={() => handleCancel()}>Cancel</Button>}
+        saveButton={
+          <Button buttonType="primary" type="submit">
+            Save
+          </Button>
+        }
+        stickyFooter
+      >
+        <Box m={2}>
+          <Textbox label="Textbox" onChange={() => {}} />
+          <Textbox label="Textbox" onChange={() => {}} />
+          <Textbox label="Textbox" onChange={() => {}} />
+          <Textbox label="Textbox" onChange={() => {}} />
+          <Textbox label="Textbox" onChange={() => {}} />
+          <Textbox label="Textbox" onChange={() => {}} />
+        </Box>
+      </Form>
+    </PopoverContainer>
+  );
+};
+FocusButton.storyName = "Focus Button Programmatically";
diff --git a/src/components/popover-container/popover-container.style.ts b/src/components/popover-container/popover-container.style.ts
index 0570e1dc6..a4ce886d1 100644
--- a/src/components/popover-container/popover-container.style.ts
+++ b/src/components/popover-container/popover-container.style.ts
@@ -5,11 +5,25 @@ import { TransitionStatus } from "react-transition-group";
 import { baseTheme } from "../../style/themes";
 import IconButton from "../icon-button";
 import StyledIcon from "../icon/icon.style";
+import {
+  StyledForm,
+  StyledFormContent,
+  StyledFormFooter,
+} from "../form/form.style";
+
+type PopoverContainerWrapperProps = {
+  hasFullWidth?: boolean;
+};
 
-const PopoverContainerWrapperStyle = styled.div`
+const PopoverContainerWrapperStyle = styled.div<PopoverContainerWrapperProps>`
   position: relative;
   display: inline-block;
-  width: 100%;
+
+  ${({ hasFullWidth }) =>
+    hasFullWidth &&
+    css`
+      width: 100%;
+    `}
 `;
 
 const PopoverContainerHeaderStyle = styled.div`
@@ -71,6 +85,25 @@ const PopoverContainerContentStyle = styled.div<PopoverContainerContentStyleProp
   :focus {
     outline: none;
   }
+
+  &:has(${StyledForm}.sticky) {
+    display: flex;
+    flex-direction: column;
+    padding: 0;
+
+    ${StyledForm}.sticky {
+      ${StyledFormContent} {
+        flex-grow: 1;
+        min-height: 0;
+        overflow-y: auto;
+      }
+
+      ${StyledFormFooter} {
+        border-bottom-right-radius: var(--borderRadius200);
+        border-bottom-left-radius: var(--borderRadius200);
+      }
+    }
+  }
 `;
 
 type AdditionalIconButtonProps = {
diff --git a/src/hooks/__internal__/useFocusPortalContent/useFocusPortalContent.tsx b/src/hooks/__internal__/useFocusPortalContent/useFocusPortalContent.tsx
index 1029177f4..52db998b4 100644
--- a/src/hooks/__internal__/useFocusPortalContent/useFocusPortalContent.tsx
+++ b/src/hooks/__internal__/useFocusPortalContent/useFocusPortalContent.tsx
@@ -15,30 +15,33 @@ export default (
             /* istanbul ignore next */ [],
         );
 
+        const filteredFocusableElements = focusableElementsInContainer.filter(
+          (el) => Number(el.tabIndex) !== -1,
+        );
+
         if (target?.current === document.activeElement) {
           if (
             Events.isTabKey(ev) &&
             !Events.isShiftKey(ev) &&
-            focusableElementsInContainer[0]
+            filteredFocusableElements[0]
           ) {
             ev.preventDefault();
-            focusableElementsInContainer[0]?.focus();
+            filteredFocusableElements[0]?.focus();
           }
 
           return;
         }
 
         /* istanbul ignore if */
-        if (!focusableElementsInContainer.length) {
+        if (!filteredFocusableElements.length) {
           return;
         }
 
         const lastElementFocused =
-          focusableElementsInContainer[
-            focusableElementsInContainer.length - 1
-          ] === document.activeElement;
+          filteredFocusableElements[filteredFocusableElements.length - 1] ===
+          document.activeElement;
         const firstElementFocused =
-          focusableElementsInContainer[0] === document.activeElement;
+          filteredFocusableElements[0] === document.activeElement;
 
         if (Events.isTabKey(ev)) {
           // last element focused inside portal navigate to next element in DOM after the target/ trigger element


Test patch:
diff --git a/src/components/popover-container/popover-container-test.stories.tsx b/src/components/popover-container/popover-container-test.stories.tsx
index c443f2b0e..a13ed84ab 100644
--- a/src/components/popover-container/popover-container-test.stories.tsx
+++ b/src/components/popover-container/popover-container-test.stories.tsx
@@ -252,6 +252,7 @@ export const WithFullWidthButton = () => {
   return (
     <PopoverContainer
       title="This is the title"
+      hasFullWidth
       renderOpenComponent={({ ref, ...rest }) => (
         <Button
           iconPosition="after"
diff --git a/src/components/popover-container/popover-container.test.tsx b/src/components/popover-container/popover-container.test.tsx
index 987dcd582..24e935baa 100644
--- a/src/components/popover-container/popover-container.test.tsx
+++ b/src/components/popover-container/popover-container.test.tsx
@@ -1,15 +1,11 @@
-import React from "react";
-import {
-  render,
-  screen,
-  act,
-  fireEvent,
-  waitFor,
-} from "@testing-library/react";
+import React, { useRef } from "react";
+import { render, screen, act, waitFor } from "@testing-library/react";
 import userEvent from "@testing-library/user-event";
 import { testStyledSystemPadding } from "../../__spec_helper__/__internal__/test-utils";
 
-import PopoverContainer from "./popover-container.component";
+import PopoverContainer, {
+  PopoverContainerHandle,
+} from "./popover-container.component";
 import { Select, Option } from "../select";
 import useMediaQuery from "../../hooks/useMediaQuery";
 import Button from "../button";
@@ -260,8 +256,9 @@ test("popup traps focus when shouldCoverButton prop is true", async () => {
     </PopoverContainer>,
   );
 
+  await user.tab();
   const closeButton = screen.getByRole("button", { name: "close" });
-  fireEvent.focus(closeButton);
+  expect(closeButton).toHaveFocus();
 
   await user.tab();
 
@@ -276,8 +273,9 @@ test("popup allows outside focus when shouldCoverButton prop is false", async ()
     </PopoverContainer>,
   );
 
+  await user.tab();
   const closeButton = screen.getByRole("button", { name: "close" });
-  fireEvent.focus(closeButton);
+  expect(closeButton).toHaveFocus();
 
   await user.tab();
 
@@ -391,15 +389,15 @@ describe("opening the popup", () => {
     },
   );
 
-  it("open button still has focus after popup is opened", async () => {
+  it("moves focus to dialog when popup is opened", async () => {
     const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
     render(<PopoverContainer>Ta da!</PopoverContainer>);
 
     const button = screen.getByRole("button");
     await user.click(button);
-    await screen.findByRole("dialog");
+    const dialog = await screen.findByRole("dialog");
 
-    expect(button).toHaveFocus();
+    expect(dialog).toHaveFocus();
   });
 });
 
@@ -681,6 +679,46 @@ test("if only the open trigger is the only focusable element on screen, when the
   expect(openButton).toHaveFocus();
 });
 
+test("should call the exposed `focusButton` method and focus the open button", async () => {
+  const MockComponent = () => {
+    const ref = useRef<PopoverContainerHandle>(null);
+
+    return (
+      <>
+        <Button
+          onClick={() => {
+            ref.current?.focusButton();
+          }}
+        >
+          Focus
+        </Button>
+        <PopoverContainer title="My popup" ref={ref} />
+      </>
+    );
+  };
+
+  const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
+  render(<MockComponent />);
+
+  await user.click(screen.getByRole("button", { name: "Focus" }));
+
+  const openButton = screen.getByRole("button", { name: "My popup" });
+  expect(openButton).toHaveFocus();
+});
+
+// coverage
+test("renders with correct width when hasFullWidth prop is true", () => {
+  render(
+    <PopoverContainer title="My popup" hasFullWidth>
+      Ta da!
+    </PopoverContainer>,
+  );
+
+  expect(screen.getByTestId("popover-container")).toHaveStyle({
+    width: "100%",
+  });
+});
+
 testStyledSystemPadding(
   (props) => (
     <PopoverContainer open title="My popup" {...props}>