Repository: Sage/carbon (ts)

Issue:
Allow different heading levels to be used in Setting Row component 
### Desired behaviour

When using the 'Setting Row' component, have the ability to choose what level of heading you require for the 'Title' element. This will resolve the accessibility issue of using headings in non-sequential order. 

Similar issue to https://github.com/Sage/carbon/issues/4607 

### Current behaviour

The 'Setting Row' component Title always uses a `h1` for the Title element. 

### Suggested Solution

Allowing use of heading styles defined in the Typography component, or more flexibility in the Heading component to choose which level of heading you require. 

### CodeSandbox or Storybook URL

https://carbon.sage.com/?path=/docs/setting-row--default-story

### Anything else we should know?

### Confidentiality

- [X] I confirm there is no confidential or commercially sensitive information included.

Pull request:
feat(settings-row, heading): surface headingType prop on components
fix #5723

### Proposed behaviour

<!--
A clear and concise description of what changes this PR makes.

If applicable, add screenshots of a codesandbox to help explain your request. You can paste these directly into GitHub.

Please DO NOT share screenshots or the source code of your project.

You can create a codesandbox to show the behaviour before/after this pull request by forking this template https://codesandbox.io/s/carbon-quickstart-j5pb2

If you include a CodeSandbox link, the bot will fork it with the new built version of carbon.
If you have a commit that includes fixes #XXXX and issue #XXXX has a CodeSandbox link in the body, the bot will fork
it with the new built version of carbon.
-->

This change will surface the `headingType` prop on the `SettingsRow` and `Heading` components to provide consumers with the means to explicitly define which `<h>` tag they would like to be rendered when the `title` prop is passed in `SettingsRow` and in the `Heading` component itself. This will ensure a proper order of importance is established within the entire page when the components are used or re-used. Each `string` from `h1-h5` will each represent one of the six HTML Section Heading elements, ensuring a proper web page hierarchy can be created, to improve readability and accessibility. 

### Current behaviour

<!--
A clear and concise description of the behaviour before this change.

If applicable, add screenshots. You can paste these directly into GitHub.
-->

Currently, when the `title` prop is passed within the `SettingsRow` component, or the `Heading` component is used, a `<h1>` tag is rendered by default. If the components were used multiple times in one page, this would mean multiple `<h1>` tags would be rendered, which goes against the recommended web standard. Furthermore, as there is currently no flexibility regarding what HTML Section Heading elements are used, a proper order of section importance can not be established.

### 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
- [x] All themes are supported if required
- [x] Unit tests added or updated if required
- [x] 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
- [x] Typescript `d.ts` file added or updated if required
- [ ] Related docs have been updated if required

#### QA

- [ ] Tested in CodeSandbox/storybook
- [ ] Add new Cypress 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? -->

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/heading/heading.component.tsx b/src/components/heading/heading.component.tsx
index 133ec8bd1..58ffa6bb8 100644
--- a/src/components/heading/heading.component.tsx
+++ b/src/components/heading/heading.component.tsx
@@ -20,6 +20,7 @@ import {
 } from "./heading.style";
 import useLocale from "../../hooks/__internal__/useLocale";
 
+export type HeadingType = "h1" | "h2" | "h3" | "h4" | "h5";
 export interface HeadingProps extends MarginProps, TagProps {
   /** Child elements */
   children?: React.ReactNode;
@@ -31,6 +32,8 @@ export interface HeadingProps extends MarginProps, TagProps {
   subheader?: React.ReactNode;
   /** Defines the subtitle id for the heading. */
   subtitleId?: string;
+  /** Defines the HTML heading element of the title. */
+  headingType?: HeadingType;
   /** Defines the help text for the heading. */
   help?: string;
   /** Defines the help link for the heading. */
@@ -66,6 +69,7 @@ export const Heading = ({
   separator = false,
   subheader,
   subtitleId,
+  headingType = "h1",
   title,
   titleId,
   ...rest
@@ -141,7 +145,7 @@ export const Heading = ({
         <StyledHeaderContent>
           <StyledHeadingTitle
             withMargin={!!pills || !!help}
-            variant="h1"
+            variant={headingType}
             data-element="title"
             id={titleId}
           >
diff --git a/src/components/heading/heading.spec.tsx b/src/components/heading/heading.spec.tsx
index 68de7accc..f9e07ab50 100644
--- a/src/components/heading/heading.spec.tsx
+++ b/src/components/heading/heading.spec.tsx
@@ -1,6 +1,6 @@
 import React from "react";
 import { shallow, mount, ReactWrapper } from "enzyme";
-import Heading from ".";
+import Heading, { HeadingType } from ".";
 import {
   StyledHeader,
   StyledSubHeader,
@@ -41,6 +41,19 @@ describe("Heading", () => {
     });
   });
 
+  describe("when headingType prop is provided", () => {
+    it.each<HeadingType>(["h1", "h2", "h3", "h4", "h5"])(
+      "HTML heading element is correct when headingType is %s",
+      (headingType) => {
+        const wrapper = mount(
+          <Heading headingType={headingType} title="foo" />
+        );
+
+        expect(wrapper.find(headingType).text()).toBe("foo");
+      }
+    );
+  });
+
   describe("when the help prop is provided", () => {
     it("renders a help component", () => {
       const wrapper = mount(
diff --git a/src/components/heading/heading.stories.mdx b/src/components/heading/heading.stories.mdx
index 0d5d72ee6..2a0ee3c39 100644
--- a/src/components/heading/heading.stories.mdx
+++ b/src/components/heading/heading.stories.mdx
@@ -42,6 +42,21 @@ import Heading from "carbon-react/lib/components/heading";
   </Story>
 </Canvas>
 
+### Heading with headingType
+
+The `headingType` prop sets the HTML heading element which is rendered on the page. It can take values `"h1"` up to `"h5"`.
+
+<Canvas>
+  <Story name="with headingType">
+    <Heading headingType="h1" title="This is a h1 Title" />
+    <Heading headingType="h2" title="This is a h2 Title" />
+    <Heading headingType="h3" title="This is a h3 Title" />
+    <Heading headingType="h4" title="This is a h4 Title" />
+    <Heading headingType="h5" title="This is a h5 Title" />
+  </Story>
+</Canvas>
+
+
 ### Heading without Divider
 
 <Canvas>
diff --git a/src/components/heading/index.ts b/src/components/heading/index.ts
index 7fe192dc3..5ef54b939 100755
--- a/src/components/heading/index.ts
+++ b/src/components/heading/index.ts
@@ -1,2 +1,2 @@
 export { default } from "./heading.component";
-export type { HeadingProps } from "./heading.component";
+export type { HeadingProps, HeadingType } from "./heading.component";
diff --git a/src/components/settings-row/settings-row.component.js b/src/components/settings-row/settings-row.component.js
index 2b57297dc..94f1afd0b 100644
--- a/src/components/settings-row/settings-row.component.js
+++ b/src/components/settings-row/settings-row.component.js
@@ -17,6 +17,7 @@ const marginPropTypes = filterStyledSystemMarginProps(
 
 const SettingsRow = ({
   title,
+  headingType = "h3",
   description,
   children,
   className,
@@ -28,6 +29,7 @@ const SettingsRow = ({
 
     return (
       <Heading
+        headingType={headingType}
         title={title}
         subheader={description}
         separator={description !== undefined}
@@ -58,6 +60,8 @@ SettingsRow.propTypes = {
   className: PropTypes.string,
   /**  A title for this group of settings. */
   title: PropTypes.string,
+  /** Defines the HTML heading element of the `title` within the component. */
+  headingType: PropTypes.oneOf(["h1", "h2", "h3", "h4", "h5"]),
   /**  A string or JSX object that provides a short description about the group of settings. */
   description: PropTypes.node,
   /** Shows a divider below the component. */
diff --git a/src/components/settings-row/settings-row.d.ts b/src/components/settings-row/settings-row.d.ts
index e45343c38..c4ab0515e 100644
--- a/src/components/settings-row/settings-row.d.ts
+++ b/src/components/settings-row/settings-row.d.ts
@@ -1,10 +1,13 @@
 import * as React from "react";
+import { HeadingType } from "../heading";
 
 export interface SettingsRowProps {
   /**  The CSS classes to apply to the component. */
   className?: string;
   /**  A title for this group of settings. */
   title?: string;
+  /** Defines the HTML heading element of the `title` within the component. */
+  headingType?: HeadingType;
   /**  A string or JSX object that provides a short description about the group of settings. */
   description?: React.ReactNode;
   /** Shows a divider below the component. */
diff --git a/src/components/settings-row/settings-row.spec.js b/src/components/settings-row/settings-row.spec.js
index 3937e4f80..c7ed410e3 100644
--- a/src/components/settings-row/settings-row.spec.js
+++ b/src/components/settings-row/settings-row.spec.js
@@ -20,6 +20,7 @@ describe("SettingsRow", () => {
   describe("render", () => {
     const name = "foobar-row";
     const title = "Some Title";
+    const description = <span>Some descriptive text</span>;
     const childId = "my_child";
     const children = <span id={childId} />;
     let wrapper = shallow(
@@ -58,7 +59,6 @@ describe("SettingsRow", () => {
     });
 
     describe("when description is provided", () => {
-      const description = <span>Some descriptive text</span>;
       let head;
 
       beforeEach(() => {
@@ -77,6 +77,25 @@ describe("SettingsRow", () => {
       });
     });
 
+    describe("when headingType prop is provided", () => {
+      it.each(["h1", "h2", "h3", "h4", "h5"])(
+        "HTML heading element is correct when headingType is %s",
+        (headingType) => {
+          wrapper = mount(
+            <SettingsRow
+              headingType={headingType}
+              title={title}
+              description={description}
+            >
+              Content for settings
+            </SettingsRow>
+          );
+
+          expect(wrapper.find(headingType).text()).toBe(title);
+        }
+      );
+    });
+
     describe("when title is not provided", () => {
       it("does not render a header", () => {
         wrapper = shallow(
diff --git a/src/components/settings-row/settings-row.stories.mdx b/src/components/settings-row/settings-row.stories.mdx
index 6d91c8499..a442e3f55 100644
--- a/src/components/settings-row/settings-row.stories.mdx
+++ b/src/components/settings-row/settings-row.stories.mdx
@@ -44,6 +44,29 @@ All `children` are rendered in the input column to the right of the header colum
   </Story>
 </Canvas>
 
+### with HeadingType
+
+The `headingType` prop sets the HTML heading element of the  `title` within the component which is rendered on the page. It can take values `"h1"` up to `"h5"`.
+<Canvas>
+  <Story name="headingType">
+    <SettingsRow headingType="h1" description="Description" title="This is a h1 Title">
+      Content for settings
+    </SettingsRow>
+    <SettingsRow headingType="h2" description="Description" title="This is a h2 Title">
+      Content for settings
+    </SettingsRow>
+    <SettingsRow headingType="h3" description="Description" title="This is a h3 Title">
+      Content for settings
+    </SettingsRow>
+    <SettingsRow headingType="h4" description="Description" title="This is a h4 Title">
+      Content for settings
+    </SettingsRow>
+    <SettingsRow headingType="h5" description="Description" title="This is a h5 Title">
+      Content for settings
+    </SettingsRow>
+  </Story>
+</Canvas>
+
 ## Props
 
 ### Settings Row
diff --git a/src/components/settings-row/settings-row.style.js b/src/components/settings-row/settings-row.style.js
index 02f067dfe..e7ca34a0a 100644
--- a/src/components/settings-row/settings-row.style.js
+++ b/src/components/settings-row/settings-row.style.js
@@ -1,11 +1,7 @@
 import styled, { css } from "styled-components";
 import { margin } from "styled-system";
 import baseTheme from "../../style/themes/base";
-import {
-  StyledHeader,
-  StyledHeadingTitle,
-  StyledSeparator,
-} from "../heading/heading.style";
+import { StyledHeader, StyledSeparator } from "../heading/heading.style";
 
 export const StyledSettingsRow = styled.div`
   ${margin}
@@ -29,15 +25,6 @@ export const StyledSettingsRow = styled.div`
     margin-bottom: 0;
   }
 
-  ${StyledHeadingTitle} {
-    color: var(--colorsUtilityYin090);
-    font-size: 15px;
-    font-weight: bold;
-    line-height: 18px;
-    margin-bottom: 10px;
-    text-transform: uppercase;
-  }
-
   ${StyledSeparator} {
     margin-bottom: 17px;
   }


Test patch:
diff --git a/src/components/heading/heading.test.js b/src/components/heading/heading.test.js
index 51a798d95..dad444e6c 100644
--- a/src/components/heading/heading.test.js
+++ b/src/components/heading/heading.test.js
@@ -152,6 +152,19 @@ context("Testing Heading component", () => {
       }
     );
 
+    describe("when headingType prop is provided", () => {
+      it.each(["h1", "h2", "h3", "h4", "h5"])(
+        "should check HTML heading element is correct when headingType is %s",
+        (headingType) => {
+          CypressMountWithProviders(
+            <HeadingComponent headingType={headingType} title="foo" />
+          );
+
+          cy.get(headingType).contains("foo");
+        }
+      );
+    });
+
     describe("should render Heading component and check accessibility issues", () => {
       it("should check heading accessibility", () => {
         CypressMountWithProviders(<HeadingComponent />);
diff --git a/src/components/settings-row/settings-row.test.js b/src/components/settings-row/settings-row.test.js
index e1df5a44a..bf634f4f6 100644
--- a/src/components/settings-row/settings-row.test.js
+++ b/src/components/settings-row/settings-row.test.js
@@ -27,6 +27,21 @@ context("Tests for SettingsRow component", () => {
       }
     );
 
+    it.each(["h1", "h2", "h3", "h4", "h5"])(
+      "should check HTML heading element is correct when headingType is %s",
+      (headingType) => {
+        CypressMountWithProviders(
+          <SettingsRowComponent
+            headingType={headingType}
+            title="foo"
+            description="bar"
+          />
+        );
+
+        cy.get(headingType).contains("foo");
+      }
+    );
+
     it.each(testData)(
       "should check %s as description for SettingsRow component",
       (description) => {