A form element consists of a fieldset and it has a legend.
Helper text at the top of the form indicating how required fields are marked with an asterisk *
The helper text is programmatically associated with the fieldset via aria-describedby.
Submit button is always interactive [avoid disabled submit buttons to indicate the form is not complete].
Submit button has a type="submit".
Inline errors can appear dynamically but they should not own aria-live or role="alert". This helps reduce screen reader announcement collision or interruptions.
Upon submission, keyboard focus moves to the first field with the error.
Errors are programmatically associated with aria-describedby pointing to a unique ID found on the element wrapping the error message.
Required fields have the required attribute.
Form fields with errors have aria-invalid="true".
When errors are fixed by the user, automatically remove those errors from the page and remove aria-invalid="true" and reference to the error in aria-describedby.