Problem/Motivation
If "required" validation on a field without a #title fails, we display an error region with no message.
Submitting as critical because we just silently fail on a form submission which can give the impression the submission was successful to the end user.
To reproduce the problem,
- Create or edit a view with a block display. For example, use "Who's online block".
- Add an exposed text filter. For example, add a filter on "Name (raw)".
- Make the field required.
- Do not supply a default value.
- Remove the Label.
- Under "Advanced", change "Use AJAX" to "Yes".
- Save the view.
- Enable the Contact module.
- Add the block with the exposed filter to the contact page (
/contact/feedbackby default). - Visit the contact page.
When the page loads, even before you try to submit any form, you should see the empty error message.
Instead of using the Contact module, you could use a view with both page and block displays. Then add the block to the page created by the same view. There are alternative steps to reproduce in Comment #61.
The current behavior fails several WCAG requirements:
- (Level A): see Error Identification: Understanding SC 3.3.1
- (Level A): see Labels or Instructions
- (Level AA): see Error Instructions
- (Level AA): see Error Prevention (Legal, Financial, Data)
- (Level A): see Name, Role, Value
See Comments #62 and #64 for more information on these accessibility issues.
Proposed resolution
Display the ID of the form element as opposed to displaying nothing so it is clear that validation failed to developers (and end users - if developers don't find this bug in their own testing)
Remaining tasks
- Accessibility review (notes in Comments #62 and #64 about how to assess this).
- Decide on final wording. See discussion in Comment #61.
User interface changes
An error message now appears when validation fails:

or (with the inline_form_errors module enabled and the wording suggested in Comment #61)

API changes
N/A
Data model changes
N/A
| Comment | File | Size | Author |
|---|---|---|---|
| #81 | after_patch.png | 506.4 KB | smustgrave |
| #81 | before_patch.png | 881.5 KB | smustgrave |
| #80 | afterpatch-77.png | 37.6 KB | asha nair |
| #80 | beforePatc -77.png | 48.47 KB | asha nair |
| #79 | interdiff_77-79.txt | 1.31 KB | ravi.shankar |
Comments
Comment #2
stefan.r commentedComment #3
cilefen commentedThis does not meet the criteria for a critical bug.
Comment #4
stefan.r commentedIf data from a webform is never submitted and the end user thinks it is how is that not data loss? :)
Comment #5
drupalove commentedI think form submission of data failing silently is critical. I can't believe this bug existed all this time.
Displaying the form ID which always exists and is descriptive despite it contains the hyphens I think is acceptable.
Comment #6
stefan.r commentedYes, if we don't have a #title, the only things that are close to describing what the form element does are #id and #name... #id we can be sure that it's always set, and it certainly beats failing silently.
Comment #7
fabianx commentedRTBC - looks great to me!
Comment #8
stefan.r commentedThanks @Fabianx - clarifying the title.
Comment #9
David_Rothstein commentedThis actually affects Drupal 8 too - the impact is lessened there due to HTML5 validation, but I assume a decent number of people will want to turn off HTML5 validation on real sites anyway (since with current browsers it's pretty annoying).
I don't think this is critical really - there is still some visual indication that the form didn't submit (just really bad visual indication) and overall nothing breaks, it's just bad user experience. Plus as recommended in the code comment, you really shouldn't have a form element with no #title anyway...
The patch looks like an improvement, but it's adding a new translatable string for no reason (
t('!name...')would work just as well ast('!id...')). And displaying the ID will have almost no meaning to end users here and will probably confuse them. If we're willing to add a new translatable string to fix this (which I think we are) then why not something like "The highlighted field is required", "A required field was not filled out", or similar?Comment #10
stefan.r commentedIn some cases there is _no_ visual indication/highlighting at all in D7. Which may be a separate bug, but it explains the criticalness there, and why "the highlighted field is required" wouldnt work.
The lack of highlighting where it's problematic and what makes this very hard to debug as there's actual data loss with webforms and such. I think we should keep the ID - it's usually indicative of the problematic field.
Comment #11
David_Rothstein commentedTrue, I guess for things like radios or checkboxes there might not be any visual indication currently.
Here's a patch for Drupal 8 to move this along. I would still lean towards something like "A required field was not filled out" myself, but this continues to use the ID in the message for now.
Comment #12
stefan.r commentedManually tested this and this works great! Can we add an automated test?
It's not just radios/checkboxes that were problematic, also some textfields from contrib modules. Not sure if it was custom styling or a separate bug but I've seen the lack of highlighting on several sites with search API exposed search fields.
Because of the lack of highlighting I think "A required field was not filled out" is problematic as we sometimes process various forms in the same request (in D7 at least, which may be a separate bug) and the "required" field may be in a different form altogether (e.g. the search box on top of the site when submitting a webform).
I agree outputting the ID is not very user-friendly, but this is an edge case (as #title will often be set) and if we don't point to the field we are leaving out some crucial information. Often people will still be able to tell which field we refer to based on the ID (especially developers, who will hopefully catch this error during testing/development)
Comment #15
nlisgo commentedI will take on the task of adding test coverage for this.
Comment #16
nlisgo commented#id is also not mandatory and we need to check that it is set before we try to use it. This patch addresses this but if the aim of this issue is to ensure that an error message is sent it might be better to use a generic error message such as 'Field is required.'
Comment #17
stefan.r commentedI'm pretty sure #id is always set by the time this code is executed, see FormBuilder::doBuildForm():
Comment #18
stefan.r commentedI disagree about a "Field is required." message being sufficient.
The required form element may be in a completely different part of the page and not highlighted, and too hard to identify when we merely hint at "some" field being required without pointing out which one.
It's also not a very useful message to post to an issue queue or to Google for as a developer/site builder. We shouldn't have to force them into using a debugger.
We're catering to an edge case (#title not being set). In most cases, #title will be set and we'll just use that.
Comment #19
nlisgo commented@stefan.r I did some debugging around the failing test in #11 to determine what the #id was for the field and there was no #id set. I will investigate some more around the code that you mentioned in #17.
Comment #20
stefan.r commentedHmm in D7 the only way to reach the form validation was right after building the form in drupal_process_form().
The D8 equivalent is FormBuilder::processForm(), which within core seems to be the only place calling FormValidator::validateForm(), and the core.api.php docs state "Forms are defined as classes that implement the \Drupal\Core\Form\FormInterface and are built using the \Drupal\Core\Form\FormBuilder class."
So it seems we can be reasonably sure that on a form array the #id will always be set and the unit test itself was "wrong". That said, it can't hurt to leave the else statement there just in case someone does somehow pass in a form that wasn't built using the form builder (and in such case a "Field is required" might actually be appropriate as we don't even have a ID to display).
Comment #21
stefan.r commentedSo the current patch may be fine, leaving CNW as this could still use a test that asserts for the ID error message.
Comment #22
nlisgo commentedformBuilder does not seem to be triggered in Drupal\Tests\Core\Form\FormValidatorTest::testRequiredErrorMessage()
The form is manually prepared and passed directly to the FormValidator.
Given that a form element can be passed to a validator without the #id being set then I still think we should check that it exists before attempting to display it.
I've added a test case where the #id is set.
Comment #23
stefan.r commentedYeah that sounds right, it's not triggered because it's a unit test but we don't document anywhere that #id must be set (nor do we fail when it isn't), or that $form must have been built using the FormBuilder.
Patch looks good, unit test passes locally so RTBC for me. Leaving at NR for someone else to have a look at this as I had written the original patch.
Comment #24
drupalove commentedThanks guys for your effort.
Can I suggest we have two short comments similar to:
// Identify the required form element by its title.
and
// Otherwise, identify the required form element by its ID.
Comment #25
drupalove commentedEven more accurate:
Include the element title in the error message.
and
Otherwise, display the element ID in the error message.
Comment #26
lomo commentedThis is a pretty nasty bug, so I'd like to see this get fixed. My only change here was to add the comments suggested in #24/#25.
I think this is RTBC-able, but since I made *any* kind of patch, I probably should not be the one to set that status. ;-)
Comment #27
fabianx commentedRTBC - looks great to me.
Comment #28
stefan.r commentedThanks @Fabianx! RTBC++
Comment #29
catchComment #30
tim.plunkettJust tweaking the comments. Looks like a reasonable change to FormValidator.
Comment #31
tim.plunkettComment #32
stefan.r commentedThanks!
Comment #33
webchickLooking at the "after" screenshot up there, that definitely isn't going to fly. There is no way for a content author to understand what field that is when we're exposing HTML ID details that would only be visible to them in view source.
The core committers talked about this on our triage call, and while the bug would be great to fix, this isn't a regression from D7 (it's rather an existing bug in D7), so not something we need to prioritize during RC (we could just as easily fix this in a patch/minor release). Additionally, we need to solve it a different way (e.g. making #title required for #required fields, or having a known label property to get some kind of human-readable string).
Un-marking RC target and needs working.
Comment #34
stefan.r commentedThis is not just affecting content authors, it also affects end users submitting any kind of form.
In Drupal 7 this issue is critical IMO so it would be good if we could get this into 8.0.1.
Let's change the message to "A required field was not filled out" as suggested by David_Rothstein.
The ID is still useful debugging information, so that could be in a trigger_error (in addition to the regular message) so that it only displays on development sites (and so that it's logged). Production sites are assumed to have error display turned off, and if they are turned on against our advice, content authors may end up seeing error messages far more obscure than something containing a HTML ID anyway.
Comment #35
stefan.r commentedComment #37
tim.plunkettWe're not actually displaying the element ID any more, so why not just improve the else case?
Why do we need this here? Also if we add it, it should be tested.
Comment #38
stefan.r commented1 makes sense! As to 2, I believe a trigger_error() is useful for site builder debugging purposes, as the required field is not always immediately visible.
Comment #39
stefan.r commentedBumping this and marking as novice, as I just ran into this issue again (where a webform submission would silently fail without any error message due to a required search field elsewhere on the page).
Comment #40
stefan.r commentedComment #41
hgoto commentedI revised the patch #35.
1. Fixed the point 1 in comment #37.
2. Added a test to test the
trigger_error().The test case became long to test the
trigger_error()...This test for
trigger_error()may be unnecessary...Anyway, I'd like this to be reviewed. Thank you.
Comment #43
stefan.r commentedPatch and test look good, and feedback from #33 and #37 has been addressed.
Can we update the screenshot in the issue summary?
Comment #44
hgoto commentedI updated the screenshot in the summary as stefan.r told.
Comment #47
djdevinI reproduced this in 8.4.x-dev. Patches address the issue and still apply to 8.4.x-dev.
Comment #48
xjmThanks @djdevin for evaluating the issue and confirming it's still valid! @catch, @cilefen, @alexpott, @Cottser, @lauriii, and I discussed and agreed this issue is indeed a major bug due to the broad usability impact of the silent failure.
Comment #51
xanoRe-roll for 8.6.x.
Comment #53
ankitjain28may commentedThe above patch contains some coding standard errors.
Comment #55
xanoThis fixes the test failure.
Can we instead trigger the error when the form is built? It'll likely expose more problems with core we'll need to fix in this issue, but the errors will show up less randomly, and earlier on (fail fast).Nah, when forms are built we can't easily figure out which elements will need a title in the end.Comment #56
xanoI added some more details to the error message, explaining this new log entry site administrators will be seeing. It links to the change record I just wrote, which includes several code examples.
Comment #57
sean_e_dietrichWorking on this as part of DrupalCon Nashville!
Comment #58
sean_e_dietrichI've been able to confirm that this patch works.
Comment #59
alexpottAs users might see this message I think we need a usability review here. To me the current text is a little odd. It implies the field needs to be a be "filled out" but potentially this could be a tickbox or select box. I think also the present tense is better and matches the error when there is a title. I'd suggest
A required field is empty.Why not just log an error using the log system?
Comment #61
benjifisherUsability review
We discussed this at the Usability Meeting today (2018-12-18): https://www.youtube.com/watch?v=9GIdotOoVy8.
Almost any text that we use will be an improvement over the current state, so thanks for working on this.
Notice that the text will be repeated below each affected field if the
inline_form_errorsmodule is enabled: see the screenshot below. That means we should try to choose text that will work both at the top of the form and also repeated beneath the empty forms.We like the suggestion in #59 better than the current patch, but we are not sure that "empty" is a good user-facing word to use. Both suggest that there is only one empty form field, when there might be more than one. Variants that allow for multiple empty fields tend to be awkward and longer than we like.
It would also be a good idea to tell the user how to fix the problem instead of describing the problem.
How about "Please enter something for each required field."? This works fairly well both at the top of the form and beneath each empty field. It tells the user how to fix the problem. It works fairly well whether there is a single empty field or several.
Here is a screenshot of the Umami theme with a custom form and my suggested text, with the
inline_form_errorsmodule enabled. (I used the browser tools to insert the recommended text.) My test form does not have titles for the input elements, but it does have descriptions: that is where the text "This input element is required and it does have a #title key." and "Same problem here!" comes from.Other points
I am adding the "Needs issue summary update" tag because the summary does not explain how to reproduce the problem. I did the following:
inline_form_errorsmodule.Comment #62
andrewmacpherson commentedI spotted this being discussed in the #UX Slack channel. I haven't read the whole issue yet, just tagging for accessibility review.
It's a WCAG failure at level A, for sure See Error Identification: Understanding SC 3.3.1.
To satisfy that WCAG success criterion, we must inform the user which input failed validation, ideally using text. In the case of FAPI elements without a #title, that's awkward because we can't use the name of the element in the message the user sees. Nonetheless, I think this can still pass WCAG "Error Identification", but it would be good to assess it carefully for all the techniques documented in WCAG.
Yes, that's very important. Some of the documented WCAG techniques may only apply when IFE is enabled.
Yes that's covered by some other WCAG success criteria. Basically all the SCs in the guideline group "Input Assistance" applies here:
Aside, how many FAPI elements lack a #title? The wider problem is avoiding that situation entirely. I think there may be a related issue sonewhere.
Comment #63
benjifisherIt is certainly good practice to supply a
#titleelement, and this issue is all about doing the best we can when people violate that standard. For example, here is what I used to test:Is there an issue somewhere to make
#titlerequired?The FAPI does set
name="enter_text_or_else"(in my example). So I think we can use a link to#enter_text_or_else(or whatever the key is in the form array). I think that @JacobRockowitz mentioned (during the Usability meeting) that the Webform module already does that. Maybe we could borrow some of his code.Comment #64
andrewmacpherson commentedI found the related issue about ensuring all FAPI elements have a #title.
Another WCAG success criterion, which I missed in #62, is "Name, Role, Value" (level A). It says all form inputs must have a programmatically-determinable accessible name. This is more strict than "tell the user how to fix the problem" - they still need to know what an input is called. The approach suggested here means we could satisfy the WCAG "Error Identification" and "Error suggestion" criteria, yet still fail "Name, Role, Value". The screenshot in #61 is an example of this - the user is aware of exactly which two inputs have errors, and that they must provide a value for both, but can't tell what each one is for.
I think it's still worth pursuing the related issue, and making FAPI #title mandatory, because it's the most reliable way to satisfy WCAG 4.1.2 "Name, Role, Value". The accessible name doesn't necessarily have to come via the FAPI #title - it could come from an
aria-labelledbyin #attributes, or a<label>created by a Twig template. But if #title isn't there, then this is a gap that module developers must fill by another means. A mandatory #title is way more robust for FAPI to ensure an associated label<label>, and wouldn't prevent themers taking different approach with aria attributes.This is a tricky issue. On the one hand, it's worth doing because it adds a level of robustness for "Error Identification" in an unusual circumstance. Yet it still leaves a hole for "Name, Role, Value" and "Labels and Instructions", so I think ensuring a #title is the more important issue to tackle.
Comment #65
benjifisher@gbirch and I worked on the steps to reproduce this issue at the ContributionWeekend2019 (Boston).
I am adding more explicit steps to reproduce, and I am summarizing Comments #62 and #64 in the issue summary.
Comment #71
savage1974 commentedThanks Xano. Your patch works on my drupal 9.1.8
best regards,
Savage
Comment #72
savage1974 commentedHi, all.
Drupal 9.1.10 - Could not apply patch #56
best regards,
Savage
Comment #75
xjmComment #76
abhijith s commentedRerolled patch #56 for 9.5.x.
Comment #77
abhijith s commentedFixing the custom command failed issue
Comment #79
ravi.shankar commentedTrying to fix failed tests of patch #79.
Comment #80
asha nair commentedApplied patch in #77 in 9.5.x-dev. Adding results as screenshots
Comment #81
smustgrave commentedTested the patch in #79
Confirmed the issue without the patch
Confirmed the patch fixed the issue.
Going to mark as reviewed but fyi there's https://www.drupal.org/project/drupal/issues/2568889#comment-14606806 to prevent the error from appearing all together because nothing was submitted.
Comment #82
quietone commentedThere are two uncompleted tasks in the Issue Summary. Setting back to NW for those items.
This is tagged for an accessibility review and that has not happened. Can someone here take that on?
Comment #84
mgiffordTagging for WCAG 3.3.1.
Comment #87
kentr commented#933004: Test that all form elements have a #title for accessibility needs review, and I think it will fix the problem in this issue.
Sounds like @andrewmacpherson also suggested that it will in #64.
I don't think this needs backport to D7 anymore.