Repository: Sage/carbon (ts)

Issue:
`VerticalMenuItem`'s settable open/close state
### Desired behaviour

When using the `VerticalMenu` component as the main app navigation with `VerticalMenuItem`s holding links to app routes and the `active` prop is set according to the url in the browser, I would like to see the nested subitem which holds a link to the currently active page when the app loads, without the need to expand the parent nav item.


### Current behaviour

As of now, when the current route matches the link which is held within a nested `VerticalMenuItem`, this item is hidden from the user until they explicitly expand the collapsible parent.

### Suggested Solution

Allow for passing a prop like `expanded` to the `VerticalMenuItem` which is a parent to other  `VerticalMenuItem`s (or provide a method to programatically set the collapsed/expanded state).

### CodeSandbox or Storybook URL

https://codesandbox.io/s/musing-keldysh-31cyh0?file=/src/App.js

### Anything else we should know?

_No response_

### Confidentiality

- [X] I confirm there is no confidential or commercially sensitive information included.

Pull request:
feat(vertical-menu): add default open state to menu item
### Proposed behaviour

Add `defaultOpen` prop to allow VerticalMenuItem children to be displayed by default

### Current behaviour

As of now, when the current route matches the link which is held within a nested VerticalMenuItem, this item is hidden from the user until they explicitly expand the collapsible parent.


### Checklist

<!-- Each PR should include the following -->

- [x] Commits follow our style guide
- [x] Related issues linked in commit messages if required
~~- [ ] Screenshots are included in the PR if useful~~
~~- [ ] All themes are supported if required~~
- [x] Unit tests added or updated if required
- [ ] Cypress 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

- [x] Tested in CodeSandbox/storybook
- [x] Add new Cypress test coverage if required
- [x] Carbon implementation matches Design System/designs
- [x] UI Tests GitHub check reviewed if required

### Additional context

closes #5822

### Testing instructions

<!-- How can a reviewer test this PR? -->

The following CodeSandbox is an example of the broken behaviour.
You can see the new behaviour by looking at the version in the comment by `codesandbox[bot]`.

<!-- Add CodeSandbox here -->


Patch:
diff --git a/src/components/vertical-menu/vertical-menu-item.component.tsx b/src/components/vertical-menu/vertical-menu-item.component.tsx
index fa6410bf9..6b0e9018c 100644
--- a/src/components/vertical-menu/vertical-menu-item.component.tsx
+++ b/src/components/vertical-menu/vertical-menu-item.component.tsx
@@ -23,6 +23,8 @@ export interface VerticalMenuItemProps<T = React.ElementType>
     TagProps {
   /** Children of the menu item - another level of VerticalMenuItems */
   children?: React.ReactNode;
+  /** Default open state of the component */
+  defaultOpen?: boolean;
   /** Title of the menu item */
   title: string;
   /** Adornment of the menu item meant to be rendered on the right side */
@@ -45,6 +47,7 @@ type InferredComponentProps<T extends React.ElementType> = Omit<
 >;
 
 export const VerticalMenuItem = <T,>({
+  defaultOpen = false,
   title,
   iconType,
   adornment,
@@ -57,7 +60,7 @@ export const VerticalMenuItem = <T,>({
 }: T extends React.ElementType
   ? InferredComponentProps<T> & VerticalMenuItemProps<T>
   : VerticalMenuItemProps) => {
-  const [isOpen, setIsOpen] = useState(false);
+  const [isOpen, setIsOpen] = useState(defaultOpen);
 
   const handleOnClick = () => {
     setIsOpen((state) => !state);
diff --git a/src/components/vertical-menu/vertical-menu-item.spec.tsx b/src/components/vertical-menu/vertical-menu-item.spec.tsx
index b207251b2..87be3064a 100644
--- a/src/components/vertical-menu/vertical-menu-item.spec.tsx
+++ b/src/components/vertical-menu/vertical-menu-item.spec.tsx
@@ -279,6 +279,18 @@ describe("VerticalMenuItem", () => {
     });
   });
 
+  describe("when the defaultOpen prop is set", () => {
+    it("then the item content should be rendered", () => {
+      render(
+        <VerticalMenuItem title="Item1" defaultOpen>
+          <VerticalMenuItem title="ChildItem1" />
+        </VerticalMenuItem>
+      );
+
+      expect(screen.getByText("ChildItem1")).toBeTruthy();
+    });
+  });
+
   it("should have the expected data attributes", () => {
     render(
       <VerticalMenuItem
diff --git a/src/components/vertical-menu/vertical-menu.stories.tsx b/src/components/vertical-menu/vertical-menu.stories.tsx
index 05499d569..05ee919a1 100644
--- a/src/components/vertical-menu/vertical-menu.stories.tsx
+++ b/src/components/vertical-menu/vertical-menu.stories.tsx
@@ -60,6 +60,7 @@ export const Default = () => {
         <VerticalMenuItem
           iconType="home"
           title="Item 3"
+          defaultOpen
           active={(isOpen) => !isOpen}
           adornment={(isOpen) =>
             !isOpen && (


Test patch:
diff --git a/src/components/vertical-menu/vertical-menu.test.js b/src/components/vertical-menu/vertical-menu.test.js
index d96a57683..1de96123a 100644
--- a/src/components/vertical-menu/vertical-menu.test.js
+++ b/src/components/vertical-menu/vertical-menu.test.js
@@ -109,7 +109,7 @@ context("Testing Vertical Menu component", () => {
       verticalMenuItem().eq(1).should("not.exist");
     });
 
-    it("should render Vertical Menu Item with adornment prop", () => {
+    it("should render Vertical Menu Item with iconType prop", () => {
       CypressMountWithProviders(<VerticalMenuItemCustom iconType="filter" />);
 
       verticalMenuItem()
@@ -120,7 +120,7 @@ context("Testing Vertical Menu component", () => {
         .and("be.visible");
     });
 
-    it("should render Vertical Menu Item with adornment prop", () => {
+    it("should render Vertical Menu Item with active prop", () => {
       CypressMountWithProviders(
         <VerticalMenuItemCustom active={(isOpen) => !isOpen} />
       );
@@ -170,6 +170,21 @@ context("Testing Vertical Menu component", () => {
         .and("be.visible");
     });
 
+    it.each([
+      [true, "be.visible"],
+      [false, "not.exist"],
+    ])(
+      "should render Vertical Menu Item opened with defaultOpen set to %s",
+      (boolean, assertion) => {
+        CypressMountWithProviders(
+          <VerticalMenuItemCustom defaultOpen={boolean} />
+        );
+
+        cy.contains("ChildItem 1").should(assertion);
+        cy.contains("ChildItem 2").should(assertion);
+      }
+    );
+
     describe("with beforeEach for VerticalMenuFullScreen", () => {
       beforeEach(() => {
         cy.viewport(320, 599);