@@ -41,6 +41,7 @@ function FormField(props) {
4141 required,
4242 type,
4343 width,
44+ id,
4445 } = props
4546
4647 const classes = cx (
@@ -58,7 +59,13 @@ function FormField(props) {
5859 const errorPointing = _ . get ( error , 'pointing' , 'above' )
5960 const errorLabel = Label . create ( error , {
6061 autoGenerateKey : false ,
61- defaultProps : { prompt : true , pointing : errorPointing } ,
62+ defaultProps : {
63+ prompt : true ,
64+ pointing : errorPointing ,
65+ id : id ? `${ id } -error-message` : undefined ,
66+ role : 'alert' ,
67+ 'aria-atomic' : true ,
68+ } ,
6269 } )
6370
6471 const errorLabelBefore = ( errorPointing === 'below' || errorPointing === 'right' ) && errorLabel
@@ -89,15 +96,21 @@ function FormField(props) {
8996 // ----------------------------------------
9097 // Checkbox/Radio Control
9198 // ----------------------------------------
92- const controlProps = { ...rest , content, children, disabled, required, type }
99+
100+ const ariaDescribedBy = id && error ? `${ id } -error-message` : null
101+ const ariaAttrs = {
102+ 'aria-describedby' : ariaDescribedBy ,
103+ 'aria-invalid' : error !== undefined ? true : undefined ,
104+ }
105+ const controlProps = { ...rest , content, children, disabled, required, type, id }
93106
94107 // wrap HTML checkboxes/radios in the label
95108 if ( control === 'input' && ( type === 'checkbox' || type === 'radio' ) ) {
96109 return (
97110 < ElementType className = { classes } >
98111 < label >
99112 { errorLabelBefore }
100- { createElement ( control , controlProps ) } { label }
113+ { createElement ( control , { ... ariaAttrs , ... controlProps } ) } { label }
101114 { errorLabelAfter }
102115 </ label >
103116 </ ElementType >
@@ -109,7 +122,7 @@ function FormField(props) {
109122 return (
110123 < ElementType className = { classes } >
111124 { errorLabelBefore }
112- { createElement ( control , { ...controlProps , label } ) }
125+ { createElement ( control , { ...ariaAttrs , ... controlProps , label } ) }
113126 { errorLabelAfter }
114127 </ ElementType >
115128 )
@@ -122,11 +135,11 @@ function FormField(props) {
122135 return (
123136 < ElementType className = { classes } >
124137 { createHTMLLabel ( label , {
125- defaultProps : { htmlFor : _ . get ( controlProps , 'id' ) } ,
138+ defaultProps : { htmlFor : id } ,
126139 autoGenerateKey : false ,
127140 } ) }
128141 { errorLabelBefore }
129- { createElement ( control , controlProps ) }
142+ { createElement ( control , { ... ariaAttrs , ... controlProps } ) }
130143 { errorLabelAfter }
131144 </ ElementType >
132145 )
@@ -161,6 +174,9 @@ FormField.propTypes = {
161174 /** Individual fields may display an error state along with a message. */
162175 error : PropTypes . oneOfType ( [ PropTypes . bool , customPropTypes . itemShorthand ] ) ,
163176
177+ /** The id of the control */
178+ id : PropTypes . string ,
179+
164180 /** A field can have its label next to instead of above it. */
165181 inline : PropTypes . bool ,
166182
0 commit comments