@@ -3,6 +3,7 @@ import styles from '@patternfly/react-styles/css/components/Radio/radio';
33import { css } from '@patternfly/react-styles' ;
44import { PickOptional } from '../../helpers/typeUtils' ;
55import { getOUIAProps , OUIAProps , getDefaultOUIAId } from '../../helpers' ;
6+ import { getUniqueId } from '../../helpers/util' ;
67
78export interface RadioProps
89 extends Omit < React . HTMLProps < HTMLInputElement > , 'disabled' | 'label' | 'onChange' | 'type' > ,
@@ -39,6 +40,8 @@ export interface RadioProps
3940 description ?: React . ReactNode ;
4041 /** Body of the radio. */
4142 body ?: React . ReactNode ;
43+ /** Custom aria-describedby value for the radio input. If not provided and description is set, a unique ID will be generated automatically. */
44+ 'aria-describedby' ?: string ;
4245 /** Sets the radio wrapper component to render. Defaults to "div". If set to "label", behaves the same as if isLabelWrapped prop was specified. */
4346 component ?: React . ElementType ;
4447 /** Value to overwrite the randomly generated data-ouia-component-id.*/
@@ -47,7 +50,7 @@ export interface RadioProps
4750 ouiaSafe ?: boolean ;
4851}
4952
50- class Radio extends Component < RadioProps , { ouiaStateId : string } > {
53+ class Radio extends Component < RadioProps , { ouiaStateId : string ; descriptionId : string } > {
5154 static displayName = 'Radio' ;
5255 static defaultProps : PickOptional < RadioProps > = {
5356 className : '' ,
@@ -63,7 +66,8 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
6366 console . error ( 'Radio:' , 'Radio requires an aria-label to be specified' ) ;
6467 }
6568 this . state = {
66- ouiaStateId : getDefaultOUIAId ( Radio . displayName )
69+ ouiaStateId : getDefaultOUIAId ( Radio . displayName ) ,
70+ descriptionId : getUniqueId ( 'pf-radio-description' )
6771 } ;
6872 }
6973
@@ -74,6 +78,7 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
7478 render ( ) {
7579 const {
7680 'aria-label' : ariaLabel ,
81+ 'aria-describedby' : ariaDescribedBy ,
7782 checked,
7883 className,
7984 inputClassName,
@@ -98,13 +103,22 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
98103 console . error ( 'Radio:' , 'id is required to make input accessible' ) ;
99104 }
100105
106+ // Handle aria-describedby logic
107+ let ariaDescribedByValue : string | undefined ;
108+ if ( ariaDescribedBy !== undefined ) {
109+ ariaDescribedByValue = ariaDescribedBy === '' ? undefined : ariaDescribedBy ;
110+ } else if ( description ) {
111+ ariaDescribedByValue = this . state . descriptionId ;
112+ }
113+
101114 const inputRendered = (
102115 < input
103116 { ...props }
104117 className = { css ( styles . radioInput , inputClassName ) }
105118 type = "radio"
106119 onChange = { this . handleChange }
107120 aria-invalid = { ! isValid }
121+ aria-describedby = { ariaDescribedByValue }
108122 disabled = { isDisabled }
109123 checked = { checked || isChecked }
110124 { ...( checked === undefined && { defaultChecked } ) }
@@ -143,7 +157,11 @@ class Radio extends Component<RadioProps, { ouiaStateId: string }> {
143157 { labelRendered }
144158 </ >
145159 ) }
146- { description && < span className = { css ( styles . radioDescription ) } > { description } </ span > }
160+ { description && (
161+ < span id = { this . state . descriptionId } className = { css ( styles . radioDescription ) } >
162+ { description }
163+ </ span >
164+ ) }
147165 { body && < span className = { css ( styles . radioBody ) } > { body } </ span > }
148166 </ Component >
149167 ) ;
0 commit comments