Repository: Sage/carbon (ts)

Issue:
ID not passed to ValidationMessage in RadioButtonGroup
### Description

On Sage 200 our automation testers are interested in being able to find validation messages by id so that they can check the content.

For most components like Textbox, I can see the id/name of the textbox ends up getting passed down to the validation as `{id/name}-validation` and our testers can use this to check an input shows the right validation text.

I can see for most inputs an id is being passed to your internal <ValidationMessage /> component but this isn't the case for the <RadioButtonGroup />.

### Reproduction

Sage/carbon/src/components/radio-button/radio-button-group/radio-button-group.component.tsx

### Steps to reproduce

_No response_

### JIRA ticket numbers (Sage only)

_No response_

### Suggested solution

Pass an id in the same way as components like Textbox do.

### Carbon version

132.2.1

### Design tokens version

4.17.0

### Relevant browsers

Firefox, Chrome, Safari, Microsoft Edge

### Relevant OSs

MacOS, Windows, Linux, Android, iOS

### Additional context

For some additional context, our automation find fields by label. Once we find a label, we can use the `for` attribute to find things like the underlying input, and we'd like to be able to do the same thing for checking things like validation messages.

### Confidentiality

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

Pull request:
feat(radio-button-group, checkbox-group): add `id` prop
fix #7191

### 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.
-->

- Add `id` prop to `RadioButtonGroup` and `CheckboxGroup`, if not provided it will be set to a randomly generated GUID. This `id` is used to set hint text and validation ids, needed for accessibility and testing purposes. 
- Tooltip validation in fieldset components will now render a visually hidden validation message to ensure proper screen reader behaviour. 
- `legendInline` in `CheckboxGroup` has no effect with new validation. 

### 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.
-->

- `RadioButtonGroup` and `CheckboxGroup` do not support `id` prop. 
- Tooltip validation messages in fieldset components does not get announced by screen readers. 
- `legendInline` in `CheckboxGroup` has unexpected behaviour with new validation. 
![image](https://github.com/user-attachments/assets/04850af4-1a9d-44cf-96eb-440030dbb606)

### 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/__internal__/fieldset/fieldset.component.tsx b/src/__internal__/fieldset/fieldset.component.tsx
index 87ba195cc..0c42b6067 100644
--- a/src/__internal__/fieldset/fieldset.component.tsx
+++ b/src/__internal__/fieldset/fieldset.component.tsx
@@ -13,6 +13,7 @@ import NewValidationContext from "../../components/carbon-provider/__internal__/
 import { InputGroupBehaviour, InputGroupContext } from "../input-behaviour";
 import useFormSpacing from "../../hooks/__internal__/useFormSpacing";
 import Help from "../../components/help";
+import Typography from "../../components/typography";
 
 export interface FieldsetProps extends MarginProps {
   /** Role */
@@ -100,13 +101,12 @@ const Fieldset = ({
   const tooltipIcon = () => {
     if (error || warning || info) {
       return (
-        <StyledIconWrapper>
+        <StyledIconWrapper aria-hidden="true">
           <ValidationIcon
             error={error}
             warning={warning}
             info={info}
             tooltipFlipOverrides={["top", "bottom"]}
-            tooltipId={validationId}
           />
         </StyledIconWrapper>
       );
@@ -171,6 +171,11 @@ const Fieldset = ({
             )}
           </InputGroupContext.Consumer>
         )}
+        {!validationRedesignOptIn && (
+          <Typography screenReaderOnly id={validationId}>
+            {error || warning || info}
+          </Typography>
+        )}
         {children}
       </StyledFieldset>
     </InputGroupBehaviour>
diff --git a/src/components/checkbox/checkbox-group/checkbox-group.component.tsx b/src/components/checkbox/checkbox-group/checkbox-group.component.tsx
index a6f32c237..e060870ca 100644
--- a/src/components/checkbox/checkbox-group/checkbox-group.component.tsx
+++ b/src/components/checkbox/checkbox-group/checkbox-group.component.tsx
@@ -1,4 +1,4 @@
-import React, { useContext } from "react";
+import React, { useContext, useRef } from "react";
 import { MarginProps } from "styled-system";
 import tagComponent from "../../../__internal__/utils/helpers/tags/tags";
 import StyledCheckboxGroup, { StyledHintText } from "./checkbox-group.style";
@@ -12,8 +12,15 @@ import ValidationMessage from "../../../__internal__/validation-message/validati
 import Box from "../../box";
 import { ErrorBorder } from "../../textbox/textbox.style";
 import CheckboxGroupContext from "./__internal__/checkbox-group.context";
+import guid from "../../../__internal__/utils/helpers/guid";
+import useInputAccessibility from "../../../hooks/__internal__/useInputAccessibility";
 
 export interface CheckboxGroupProps extends ValidationProps, MarginProps {
+  /**
+   * Unique identifier for the component.
+   * Will use a randomly generated GUID if none is provided.
+   */
+  id?: string;
   /** The content for the CheckboxGroup Legend */
   legend?: string;
   /**
@@ -43,53 +50,74 @@ export interface CheckboxGroupProps extends ValidationProps, MarginProps {
   inline?: boolean;
 }
 
-export const CheckboxGroup = (props: CheckboxGroupProps) => {
+export const CheckboxGroup = ({
+  children,
+  legend,
+  error,
+  warning,
+  info,
+  required,
+  isOptional,
+  legendInline,
+  legendWidth,
+  legendAlign = "left",
+  legendSpacing,
+  legendHelp,
+  tooltipPosition,
+  inline,
+  id,
+  ...rest
+}: CheckboxGroupProps) => {
   const { validationRedesignOptIn } = useContext(NewValidationContext);
+  const internalId = useRef(guid());
+  const uniqueId = id || internalId.current;
+  const inputHintId = legendHelp ? `${uniqueId}-hint` : undefined;
 
-  const {
-    children,
-    legend,
+  const { validationId, ariaDescribedBy } = useInputAccessibility({
+    id: uniqueId,
+    validationRedesignOptIn: true,
     error,
     warning,
     info,
-    required,
-    isOptional,
-    legendInline,
-    legendWidth,
-    legendAlign = "left",
-    legendSpacing,
-    legendHelp,
-    tooltipPosition,
-    inline,
-  } = props;
+  });
+
+  const combinedAriaDescribedBy = [ariaDescribedBy, inputHintId]
+    .filter(Boolean)
+    .join(" ");
 
   return (
     <>
       {validationRedesignOptIn ? (
         <Fieldset
+          id={uniqueId}
           legend={legend}
-          inline={legendInline}
-          legendWidth={legendWidth}
           legendAlign={legendAlign}
-          legendSpacing={legendSpacing}
           error={error}
           warning={warning}
           isRequired={required}
           isOptional={isOptional}
-          {...tagComponent("checkboxgroup", props)}
+          {...(combinedAriaDescribedBy && {
+            "aria-describedby": combinedAriaDescribedBy,
+          })}
+          {...tagComponent("checkboxgroup", rest)}
           blockGroupBehaviour={!(error || warning)}
-          {...filterStyledSystemMarginProps(props)}
+          {...filterStyledSystemMarginProps(rest)}
         >
-          {legendHelp && <StyledHintText>{legendHelp}</StyledHintText>}
+          {legendHelp && (
+            <StyledHintText id={inputHintId}>{legendHelp}</StyledHintText>
+          )}
           <Box position="relative">
-            <ValidationMessage error={error} warning={warning} />
+            <ValidationMessage
+              error={error}
+              warning={warning}
+              validationId={validationId}
+            />
             {(error || warning) && (
               <ErrorBorder warning={!!(!error && warning)} inline={inline} />
             )}
             <StyledCheckboxGroup
               data-component="checkbox-group"
               data-role="checkbox-group"
-              legendInline={legendInline}
               inline={inline}
             >
               <CheckboxGroupContext.Provider
@@ -108,6 +136,7 @@ export const CheckboxGroup = (props: CheckboxGroupProps) => {
       ) : (
         <TooltipProvider tooltipPosition={tooltipPosition}>
           <Fieldset
+            id={uniqueId}
             legend={legend}
             inline={legendInline}
             legendWidth={legendWidth}
@@ -118,9 +147,11 @@ export const CheckboxGroup = (props: CheckboxGroupProps) => {
             info={info}
             isRequired={required}
             isOptional={isOptional}
-            {...tagComponent("checkboxgroup", props)}
+            aria-describedby={ariaDescribedBy}
+            validationId={validationId}
+            {...tagComponent("checkboxgroup", rest)}
             blockGroupBehaviour={!(error || warning || info)}
-            {...filterStyledSystemMarginProps(props)}
+            {...filterStyledSystemMarginProps(rest)}
           >
             <StyledCheckboxGroup
               data-component="checkbox-group"
diff --git a/src/components/numeral-date/numeral-date.component.tsx b/src/components/numeral-date/numeral-date.component.tsx
index c0ff2d510..2f8fa6b6d 100644
--- a/src/components/numeral-date/numeral-date.component.tsx
+++ b/src/components/numeral-date/numeral-date.component.tsx
@@ -530,7 +530,7 @@ export const NumeralDate = <DateType extends NumeralDateObject = FullDate>({
           legendWidth={labelWidth}
           legendSpacing={labelSpacing}
           validationId={validationId}
-          aria-describedby={ariaDescribedBy}
+          aria-describedby={validationOnLabel ? ariaDescribedBy : fieldHelpId}
           {...filterStyledSystemMarginProps(rest)}
         >
           <Box display="flex" flexDirection="column" mt={inline ? 0 : 1}>
diff --git a/src/components/radio-button/radio-button-group/radio-button-group.component.tsx b/src/components/radio-button/radio-button-group/radio-button-group.component.tsx
index 01a90296d..15e90449b 100644
--- a/src/components/radio-button/radio-button-group/radio-button-group.component.tsx
+++ b/src/components/radio-button/radio-button-group/radio-button-group.component.tsx
@@ -1,4 +1,4 @@
-import React, { useContext } from "react";
+import React, { useContext, useRef } from "react";
 import { MarginProps } from "styled-system";
 import tagComponent from "../../../__internal__/utils/helpers/tags/tags";
 import Fieldset from "../../../__internal__/fieldset";
@@ -15,9 +15,16 @@ import NewValidationContext from "../../carbon-provider/__internal__/new-validat
 import ValidationMessage from "../../../__internal__/validation-message/validation-message.component";
 import Box from "../../box";
 import { ErrorBorder } from "../../textbox/textbox.style";
+import guid from "../../../__internal__/utils/helpers/guid";
+import useInputAccessibility from "../../../hooks/__internal__/useInputAccessibility";
 
 let deprecateUncontrolledWarnTriggered = false;
 export interface RadioButtonGroupProps extends ValidationProps, MarginProps {
+  /**
+   * Unique identifier for the component.
+   * Will use a randomly generated GUID if none is provided.
+   */
+  id?: string;
   /** Breakpoint for adaptive legend (inline labels change to top aligned). Enables the adaptive behaviour when set */
   adaptiveLegendBreakpoint?: number;
   /** Breakpoint for adaptive spacing (left margin changes to 0). Enables the adaptive behaviour when set */
@@ -28,7 +35,7 @@ export interface RadioButtonGroupProps extends ValidationProps, MarginProps {
   inline?: boolean;
   /** Spacing between labels and radio buttons, given number will be multiplied by base spacing unit (8) */
   labelSpacing?: 1 | 2;
-  /** The content for the RadioGroup Legend */
+  /** The content for the RadioButtonGroup Legend */
   legend?: string;
   /**
    * The content for the RadioButtonGroup hint text,
@@ -59,36 +66,35 @@ export interface RadioButtonGroupProps extends ValidationProps, MarginProps {
   tooltipPosition?: "top" | "bottom" | "left" | "right";
 }
 
-export const RadioButtonGroup = (props: RadioButtonGroupProps) => {
-  const {
-    children,
-    name,
-    legend,
-    legendHelp,
-    error,
-    warning,
-    info,
-    onBlur,
-    onChange,
-    value,
-    inline = false,
-    legendInline = false,
-    legendWidth,
-    legendAlign = "left",
-    legendSpacing,
-    labelSpacing = 1,
-    adaptiveLegendBreakpoint,
-    adaptiveSpacingBreakpoint,
-    required,
-    isOptional,
-    tooltipPosition,
-  } = props;
-
+export const RadioButtonGroup = ({
+  children,
+  id,
+  name,
+  legend,
+  legendHelp,
+  error,
+  warning,
+  info,
+  onBlur,
+  onChange,
+  value,
+  inline = false,
+  legendInline = false,
+  legendWidth,
+  legendAlign = "left",
+  legendSpacing,
+  labelSpacing = 1,
+  adaptiveLegendBreakpoint,
+  adaptiveSpacingBreakpoint,
+  required,
+  isOptional,
+  tooltipPosition,
+  ...rest
+}: RadioButtonGroupProps) => {
   const { validationRedesignOptIn } = useContext(NewValidationContext);
-
-  const legendInlineWithNewValidation = validationRedesignOptIn
-    ? false
-    : legendInline;
+  const internalId = useRef(guid());
+  const uniqueId = id || internalId.current;
+  const inputHintId = legendHelp ? `${uniqueId}-hint` : undefined;
 
   if (!deprecateUncontrolledWarnTriggered && !onChange) {
     deprecateUncontrolledWarnTriggered = true;
@@ -97,7 +103,7 @@ export const RadioButtonGroup = (props: RadioButtonGroupProps) => {
     );
   }
 
-  const marginProps = filterStyledSystemMarginProps(props);
+  const marginProps = filterStyledSystemMarginProps(rest);
 
   const isAboveLegendBreakpoint = useIsAboveBreakpoint(
     adaptiveLegendBreakpoint,
@@ -107,7 +113,7 @@ export const RadioButtonGroup = (props: RadioButtonGroupProps) => {
     adaptiveSpacingBreakpoint,
   );
 
-  let inlineLegend = legendInlineWithNewValidation;
+  let inlineLegend = legendInline;
   if (adaptiveLegendBreakpoint) {
     inlineLegend = !!isAboveLegendBreakpoint;
   }
@@ -117,6 +123,18 @@ export const RadioButtonGroup = (props: RadioButtonGroupProps) => {
     marginLeft = undefined;
   }
 
+  const { validationId, ariaDescribedBy } = useInputAccessibility({
+    id: uniqueId,
+    validationRedesignOptIn: true,
+    error,
+    warning,
+    info,
+  });
+
+  const combinedAriaDescribedBy = [ariaDescribedBy, inputHintId]
+    .filter(Boolean)
+    .join(" ");
+
   return (
     <>
       {validationRedesignOptIn ? (
@@ -124,20 +142,26 @@ export const RadioButtonGroup = (props: RadioButtonGroupProps) => {
           legend={legend}
           error={error}
           warning={warning}
-          inline={inlineLegend}
-          legendWidth={legendWidth}
           legendAlign={legendAlign}
-          legendSpacing={legendSpacing}
           isRequired={required}
           isOptional={isOptional}
-          {...tagComponent("radiogroup", props)}
+          {...tagComponent("radiogroup", rest)}
           {...marginProps}
           ml={marginLeft}
           blockGroupBehaviour={!(error || warning)}
+          {...(combinedAriaDescribedBy && {
+            "aria-describedby": combinedAriaDescribedBy,
+          })}
         >
-          {legendHelp && <StyledHintText>{legendHelp}</StyledHintText>}
+          {legendHelp && (
+            <StyledHintText id={inputHintId}>{legendHelp}</StyledHintText>
+          )}
           <Box position="relative">
-            <ValidationMessage error={error} warning={warning} />
+            <ValidationMessage
+              error={error}
+              warning={warning}
+              validationId={validationId}
+            />
             {(error || warning) && (
               <ErrorBorder
                 data-role="radio-error-border"
@@ -187,10 +211,12 @@ export const RadioButtonGroup = (props: RadioButtonGroupProps) => {
             legendSpacing={legendSpacing}
             isRequired={required}
             isOptional={isOptional}
-            {...tagComponent("radiogroup", props)}
+            {...tagComponent("radiogroup", rest)}
             {...marginProps}
             ml={marginLeft}
             blockGroupBehaviour={!(error || warning || info)}
+            aria-describedby={ariaDescribedBy}
+            validationId={validationId}
           >
             <RadioButtonGroupStyle
               data-component="radio-button-group"


Test patch:
diff --git a/src/__internal__/fieldset/fieldset.test.tsx b/src/__internal__/fieldset/fieldset.test.tsx
index 18f41f84a..51261c2a3 100644
--- a/src/__internal__/fieldset/fieldset.test.tsx
+++ b/src/__internal__/fieldset/fieldset.test.tsx
@@ -41,40 +41,46 @@ test("sets child inputs as required when `isRequired` is true", () => {
   expect(inputs[1]).toBeRequired();
 });
 
-test("renders validation icon when `legend` and `error` are provided", () => {
+test("renders validation icon and hidden message when `legend` and `error` are provided", () => {
   render(
-    <Fieldset legend="Legend" error="error">
+    <Fieldset legend="Legend" error="error message">
       <input />
     </Fieldset>,
   );
 
   const icon = screen.getByTestId("icon-error");
+  const message = screen.getByText("error message");
 
   expect(icon).toBeVisible();
+  expect(message).toBeInTheDocument();
 });
 
-test("renders validation icon when `legend` and `warning` are provided", () => {
+test("renders validation icon and hidden message when `legend` and `warning` are provided", () => {
   render(
-    <Fieldset legend="Legend" warning="warning">
+    <Fieldset legend="Legend" warning="warning message">
       <input />
     </Fieldset>,
   );
 
   const icon = screen.getByTestId("icon-warning");
+  const message = screen.getByText("warning message");
 
   expect(icon).toBeVisible();
+  expect(message).toBeInTheDocument();
 });
 
-test("renders validation icon when `legend` and `info` are provided", () => {
+test("renders validation icon and hidden message when `legend` and `info` are provided", () => {
   render(
-    <Fieldset legend="Legend" info="info">
+    <Fieldset legend="Legend" info="info message">
       <input />
     </Fieldset>,
   );
 
   const icon = screen.getByTestId("icon-info");
+  const message = screen.getByText("info message");
 
   expect(icon).toBeVisible();
+  expect(message).toBeInTheDocument();
 });
 
 test("renders help icon when `labelHelp` is provided", () => {
diff --git a/src/components/checkbox/checkbox-group/checkbox-group.test.tsx b/src/components/checkbox/checkbox-group/checkbox-group.test.tsx
index c352bdfca..52d85614f 100644
--- a/src/components/checkbox/checkbox-group/checkbox-group.test.tsx
+++ b/src/components/checkbox/checkbox-group/checkbox-group.test.tsx
@@ -26,18 +26,6 @@ test("should render with the provided legend", () => {
   expect(screen.getByText("legend")).toBeVisible();
 });
 
-test("should render legendHelp as a hint text when validationRedesignOptIn is true", () => {
-  render(
-    <CarbonProvider validationRedesignOptIn>
-      <CheckboxGroup legend="legend" legendHelp="legendHelp">
-        <Checkbox value="1" label="label" onChange={() => {}} />
-      </CheckboxGroup>
-    </CarbonProvider>,
-  );
-
-  expect(screen.getByText("legendHelp")).toBeVisible();
-});
-
 test("should render required checkbox children when required prop is set", () => {
   render(
     <CheckboxGroup legend="legend" required>
@@ -66,28 +54,37 @@ it("should append (optional) text on the legend when isOptional prop is set", ()
   );
 });
 
-test("should render error message when error prop is set and validationRedesignOptIn is true", () => {
+it("should render with accessible description when `error` prop is set", () => {
   render(
-    <CarbonProvider validationRedesignOptIn>
-      <CheckboxGroup legend="legend" error="error">
-        <Checkbox value="1" label="label" onChange={() => {}} />
-      </CheckboxGroup>
-    </CarbonProvider>,
+    <CheckboxGroup legend="legend" error="error message">
+      <Checkbox value="1" label="label" onChange={() => {}} />
+    </CheckboxGroup>,
   );
 
-  expect(screen.getByText("error")).toBeVisible();
+  const fieldset = screen.getByRole("group", { name: "legend" });
+  expect(fieldset).toHaveAccessibleDescription("error message");
 });
 
-test("should render warning message when warning prop is set and validationRedesignOptIn is true", () => {
+it("should render with accessible description when `warning` prop is set", () => {
   render(
-    <CarbonProvider validationRedesignOptIn>
-      <CheckboxGroup legend="legend" warning="warning">
-        <Checkbox value="1" label="label" onChange={() => {}} />
-      </CheckboxGroup>
-    </CarbonProvider>,
+    <CheckboxGroup legend="legend" warning="warning message">
+      <Checkbox value="1" label="label" onChange={() => {}} />
+    </CheckboxGroup>,
+  );
+
+  const fieldset = screen.getByRole("group", { name: "legend" });
+  expect(fieldset).toHaveAccessibleDescription("warning message");
+});
+
+it("should render with accessible description when `info` prop is set", () => {
+  render(
+    <CheckboxGroup legend="legend" info="info message">
+      <Checkbox value="1" label="label" onChange={() => {}} />
+    </CheckboxGroup>,
   );
 
-  expect(screen.getByText("warning")).toBeVisible();
+  const fieldset = screen.getByRole("group", { name: "legend" });
+  expect(fieldset).toHaveAccessibleDescription("info message");
 });
 
 test("should render with expected styles when legendInline is true", () => {
@@ -121,6 +118,71 @@ test("should render with expected styles when inline is true", () => {
   });
 });
 
+describe("when the `validationRedesignOptIn` flag is true", () => {
+  it("should render `legendHelp` as a hint text", () => {
+    render(
+      <CarbonProvider validationRedesignOptIn>
+        <CheckboxGroup legend="legend" legendHelp="legendHelp">
+          <Checkbox value="1" label="label" onChange={() => {}} />
+        </CheckboxGroup>
+      </CarbonProvider>,
+    );
+
+    const fieldset = screen.getByRole("group", { name: "legend" });
+
+    expect(screen.getByText("legendHelp")).toBeVisible();
+    expect(fieldset).toHaveAccessibleDescription("legendHelp");
+  });
+
+  it("should render with error message when `error` prop is set", () => {
+    render(
+      <CarbonProvider validationRedesignOptIn>
+        <CheckboxGroup legend="legend" error="error message">
+          <Checkbox value="1" label="label" onChange={() => {}} />
+        </CheckboxGroup>
+      </CarbonProvider>,
+    );
+
+    const fieldset = screen.getByRole("group", { name: "legend" });
+
+    expect(screen.getByText("error message")).toBeVisible();
+    expect(fieldset).toHaveAccessibleDescription("error message");
+  });
+
+  it("should render with warning message when `warning` prop is set", () => {
+    render(
+      <CarbonProvider validationRedesignOptIn>
+        <CheckboxGroup legend="legend" warning="warning message">
+          <Checkbox value="1" label="label" onChange={() => {}} />
+        </CheckboxGroup>
+      </CarbonProvider>,
+    );
+
+    const fieldset = screen.getByRole("group", { name: "legend" });
+
+    expect(screen.getByText("warning message")).toBeVisible();
+    expect(fieldset).toHaveAccessibleDescription("warning message");
+  });
+
+  it("should render with combined validation and legendHelp messages as the fieldset's accessible description", () => {
+    render(
+      <CarbonProvider validationRedesignOptIn>
+        <CheckboxGroup
+          legend="legend"
+          legendHelp="legendHelp"
+          error="error message"
+        >
+          <Checkbox value="1" label="label" onChange={() => {}} />
+        </CheckboxGroup>
+      </CarbonProvider>,
+    );
+
+    const fieldset = screen.getByRole("group", { name: "legend" });
+
+    expect(fieldset).toHaveAccessibleDescription("error message legendHelp");
+  });
+});
+
 testStyledSystemMargin(
   (props) => (
     <CheckboxGroup
diff --git a/src/components/checkbox/checkbox-test.stories.tsx b/src/components/checkbox/checkbox-test.stories.tsx
index 3b7b903a8..1362f7846 100644
--- a/src/components/checkbox/checkbox-test.stories.tsx
+++ b/src/components/checkbox/checkbox-test.stories.tsx
@@ -1,76 +1,33 @@
 import React, { useState } from "react";
 import { action } from "@storybook/addon-actions";
 
-import { Checkbox, CheckboxProps } from ".";
+import { Checkbox, CheckboxGroup, CheckboxProps, CheckboxGroupProps } from ".";
 import Box from "../box";
+import CarbonProvider from "../carbon-provider";
 
 export default {
   title: "Checkbox/Test",
-  includeStories: ["Default", "WithLongLabel"],
   parameters: {
     info: { disable: true },
     chromatic: {
       disableSnapshot: false,
     },
   },
-  argTypes: {
-    labelSpacing: {
-      options: [1, 2],
-      control: {
-        type: "select",
-      },
-    },
-    size: {
-      options: ["small", "large"],
-      control: {
-        type: "select",
-      },
-    },
-    inputWidth: {
-      control: {
-        type: "range",
-        min: 0,
-        max: 100,
-        step: 1,
-      },
-    },
-    labelWidth: {
-      control: {
-        type: "range",
-        min: 0,
-        max: 100,
-        step: 1,
-      },
-    },
-    adaptiveSpacingBreakpoint: {
-      control: {
-        type: "number",
-      },
-    },
-  },
 };
 
-export const Default = ({
-  label,
-  fieldHelp,
-  labelHelp,
-  ...args
-}: CheckboxProps) => {
+export const Default = ({ ...args }: CheckboxProps) => {
   const [isChecked, setIsChecked] = useState(false);
   const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
     const { checked } = event.target;
     setIsChecked(checked);
     action("change")(`checked: ${checked}`);
   };
+
   return (
     <Checkbox
       onChange={handleChange}
       checked={isChecked}
       onBlur={action("onBlur")}
-      label={label}
-      fieldHelp={fieldHelp}
-      labelHelp={labelHelp}
-      helpAriaLabel={labelHelp as string}
       {...args}
     />
   );
@@ -79,7 +36,7 @@ export const Default = ({
 Default.storyName = "default";
 
 Default.args = {
-  key: "",
+  id: "default",
   label: "Example Checkbox",
   autoFocus: false,
   disabled: false,
@@ -93,8 +50,29 @@ Default.args = {
   size: "small",
   value: "",
   ml: "0",
-  adaptiveSpacingBreakpoint: undefined,
+  adaptiveSpacingBreakpoint: 0,
   required: false,
+  isOptional: false,
+  helpAriaLabel: "",
+  validationOnLabel: false,
+  validationIconId: "",
+  error: "",
+  warning: "",
+  info: "",
+};
+Default.argTypes = {
+  labelSpacing: {
+    options: [1, 2],
+    control: {
+      type: "select",
+    },
+  },
+  size: {
+    options: ["small", "large"],
+    control: {
+      type: "select",
+    },
+  },
 };
 
 export const WithLongLabel = ({ label, size, ...args }: CheckboxProps) => {
@@ -111,3 +89,58 @@ WithLongLabel.args = {
   label: "A really long description that will wrap onto the next line.",
   size: "",
 };
+
+export const Validation = ({ ...args }: CheckboxGroupProps) => {
+  return (
+    <CheckboxGroup {...args}>
+      <Checkbox label="Checkbox 1" />
+      <Checkbox label="Checkbox 2" />
+    </CheckboxGroup>
+  );
+};
+Validation.storyName = "Validation";
+Validation.args = {
+  id: "validation",
+  legend: "Checkbox Group",
+  legendInline: false,
+  legendWidth: 0,
+  legendAlign: "left",
+  legendSpacing: 1,
+  error: "error message",
+  warning: "",
+  required: false,
+  isOptional: false,
+  inline: false,
+};
+Validation.argTypes = {
+  legendSpacing: {
+    options: [1, 2],
+    control: {
+      type: "select",
+    },
+  },
+};
+
+export const NewValidation = ({ ...args }: CheckboxGroupProps) => {
+  return (
+    <CarbonProvider validationRedesignOptIn>
+      <CheckboxGroup {...args}>
+        <Checkbox label="Checkbox 1" />
+        <Checkbox label="Checkbox 2" />
+      </CheckboxGroup>
+    </CarbonProvider>
+  );
+};
+NewValidation.storyName = "New validation";
+NewValidation.args = {
+  id: "new-validation",
+  legend: "Checkbox Group",
+  legendHelp: "Legend help text",
+  legendInline: false,
+  legendAlign: "left",
+  error: "error message",
+  warning: "",
+  required: false,
+  isOptional: false,
+  inline: false,
+};
diff --git a/src/components/numeral-date/numeral-date.test.tsx b/src/components/numeral-date/numeral-date.test.tsx
index 4c31e54b8..de5901b51 100644
--- a/src/components/numeral-date/numeral-date.test.tsx
+++ b/src/components/numeral-date/numeral-date.test.tsx
@@ -739,8 +739,10 @@ test("should render provided `fieldHelp` text when the `validationRedesignOptIn`
   );
 
   const fieldHelpText = screen.getByText("fieldHelp");
+  const fieldset = screen.getByRole("group");
 
   expect(fieldHelpText).toBeVisible();
+  expect(fieldset).toHaveAccessibleDescription("fieldHelp");
 });
 
 // coverage
@@ -2118,21 +2120,19 @@ test("should set the inputs to `readOnly` when the prop is passed", () => {
 
 test.each(["error", "warning", "info"])(
   "should render with expected accessible description when '%s' and 'fieldHelp' props are passed and 'validationRedesignOptIn' is false",
-  async (validation) => {
-    const user = userEvent.setup({ advanceTimers: jest.advanceTimersByTime });
+  (validation) => {
     render(
       <NumeralDate
         value={{ dd: "", mm: "", yyyy: "" }}
         onChange={() => {}}
+        label="label"
         fieldHelp="fieldHelp"
+        validationOnLabel
         {...{ [validation]: "Message" }}
       />,
     );
 
-    const dayInput = screen.getByRole("textbox", { name: "Day" });
-    await user.click(dayInput);
-
-    const fieldset = screen.getByRole("group");
+    const fieldset = screen.getByRole("group", { name: "label" });
     expect(fieldset).toHaveAccessibleDescription("fieldHelp Message");
   },
 );
diff --git a/src/components/radio-button/radio-button-group/radio-button-group.test.tsx b/src/components/radio-button/radio-button-group/radio-button-group.test.tsx
index df62dbc1d..431615f03 100644
--- a/src/components/radio-button/radio-button-group/radio-button-group.test.tsx
+++ b/src/components/radio-button/radio-button-group/radio-button-group.test.tsx
@@ -199,13 +199,13 @@ test("does not render with provided margin-left when screen is smaller than `ada
   expect(fieldset).toHaveStyle({ marginLeft: "0" });
 });
 
-// coverage
 describe("when `validationRedesignOptIn` flag is true", () => {
-  it("renders with provided `error`", () => {
+  it("renders with provided `error` message", () => {
     render(
       <CarbonProvider validationRedesignOptIn>
         <RadioButtonGroup
           name="group"
+          legend="legend"
           error="Error message"
           onChange={() => {}}
         >
@@ -214,14 +214,18 @@ describe("when `validationRedesignOptIn` flag is true", () => {
       </CarbonProvider>,
     );
 
+    const fieldset = screen.getByRole("group", { name: "legend" });
+
     expect(screen.getByText("Error message")).toBeVisible();
+    expect(fieldset).toHaveAccessibleDescription("Error message");
   });
 
-  it("renders with provided `warning`", () => {
+  it("renders with provided `warning` message", () => {
     render(
       <CarbonProvider validationRedesignOptIn>
         <RadioButtonGroup
           name="group"
+          legend="legend"
           warning="Warning message"
           onChange={() => {}}
         >
@@ -230,7 +234,10 @@ describe("when `validationRedesignOptIn` flag is true", () => {
       </CarbonProvider>,
     );
 
+    const fieldset = screen.getByRole("group", { name: "legend" });
+
     expect(screen.getByText("Warning message")).toBeVisible();
+    expect(fieldset).toHaveAccessibleDescription("Warning message");
   });
 
   it("renders `legendHelp` as hint text", () => {
@@ -238,6 +245,7 @@ describe("when `validationRedesignOptIn` flag is true", () => {
       <CarbonProvider validationRedesignOptIn>
         <RadioButtonGroup
           name="group"
+          legend="legend"
           legendHelp="Hint message"
           onChange={() => {}}
         >
@@ -246,8 +254,10 @@ describe("when `validationRedesignOptIn` flag is true", () => {
       </CarbonProvider>,
     );
 
+    const fieldset = screen.getByRole("group", { name: "legend" });
     const hintText = screen.getByText("Hint message");
 
+    expect(fieldset).toHaveAccessibleDescription("Hint message");
     expect(hintText).toBeVisible();
     expect(hintText).toHaveStyle({
       marginTop: "-4px",
@@ -296,29 +306,4 @@ describe("when `validationRedesignOptIn` flag is true", () => {
     expect(screen.getAllByRole("radio")).toHaveLength(2);
     expect(screen.getByText("foo")).toBeVisible();
   });
-
-  it("renders legend with default styling when `legendInline` is set", () => {
-    render(
-      <CarbonProvider validationRedesignOptIn>
-        <RadioButtonGroup
-          name="group"
-          data-role="radio-group-inline"
-          onChange={() => {}}
-          legendInline
-        >
-          {[
-            <RadioButton key="radio1" value="radio1" label="Radio Button 1" />,
-            null,
-            undefined,
-            "foo",
-            <RadioButton key="radio2" value="radio2" label="Radio Button 2" />,
-          ]}
-        </RadioButtonGroup>
-      </CarbonProvider>,
-    );
-
-    expect(screen.getByTestId("radio-group-inline")).not.toHaveStyle({
-      marginTop: "4px",
-    });
-  });
 });
diff --git a/src/components/radio-button/radio-button-test.stories.tsx b/src/components/radio-button/radio-button-test.stories.tsx
index a07f7c154..388a887ed 100644
--- a/src/components/radio-button/radio-button-test.stories.tsx
+++ b/src/components/radio-button/radio-button-test.stories.tsx
@@ -186,17 +186,13 @@ WithTooltipPositionOnRadioGroup.storyName =
 export const WithNewValidation = (props: Partial<RadioButtonProps>) => {
   return (
     <CarbonProvider validationRedesignOptIn>
-      <RadioButton
-        id="radio-1"
-        value="radio1"
-        label="Radiobutton 1"
-        {...props}
-      />
+      <RadioButton id="radio-1" value="radio1" {...props} />
     </CarbonProvider>
   );
 };
 
 WithNewValidation.args = {
+  label: "Radiobutton 1",
   error: true,
   warning: false,
   fieldHelp: "",
@@ -205,6 +201,8 @@ WithNewValidation.args = {
   checked: false,
   disabled: false,
   labelSpacing: 1,
+  reverse: false,
+  size: "small",
 };
 
 export const WithNewValidationGroup = ({
@@ -212,11 +210,7 @@ export const WithNewValidationGroup = ({
 }: Partial<RadioButtonGroupProps>) => {
   return (
     <CarbonProvider validationRedesignOptIn>
-      <RadioButtonGroup
-        name="radio-button-group"
-        legend="Radio group legend"
-        {...props}
-      >
+      <RadioButtonGroup name="radio-button-group" {...props}>
         <RadioButton id="radio-1" value="radio1" label="Yes" />
         <RadioButton id="radio-2" value="radio2" label="No" />
         <RadioButton
@@ -231,11 +225,14 @@ export const WithNewValidationGroup = ({
 };
 
 WithNewValidationGroup.args = {
+  id: "new-validation",
+  legend: "Radio group legend",
   error: "Error message",
   warning: "",
   legendHelp: "Legend help text",
-  legendInline: false,
+  legendAlign: "left",
   required: true,
+  isOptional: false,
   inline: false,
 };
 WithNewValidationGroup.parameters = {