| Project: | Drupal core |
| Version: | 8.x-dev |
| Component: | forms system |
| Category: | bug report |
| Priority: | major |
| Assigned: | Unassigned |
| Status: | needs work |
| Issue tags: | a11ySprint, accessibility, FAPI, form validation, Needs tests, Required Fields, Usability, User interface |
Issue Summary
The goal is to implement a new presentation of form errors in the core forms system. This will resolve a long-standing accessibility problem. In addition, we will improve UX at the same time. This issue supercedes #447816: WCAG violation: Relying on a color by itself to indicate a field validation error which has been marked as duplicate but can be referenced for the previous discussion.
What is proposed?
Move form error messages to an inline location next to the form field and label. Example screenshot:

The $messages area at the top of the page will have a brief indication of the number of errors with links to each error'ed field. The full text of each error will be inline.
This design is "Case 3" that was discussed in a Form Error Design Wiki. The wiki page has many more screen mockups of form errors in different situations such as combined form elements and mobile sized displays.
Where did this come from?
This proposal stems from the Form Error Design Wiki where we gathered feedback from accessibility stakeholders (such as Everett Zufelt) as well as UX stakeholders (yoroy, bojhan). This wiki was a new attempt to build consensus around an old problem that started in the issue queue in 2009 and had 265 comments without resolution. Let's solve this for D8!
Accessibility considerations
- More than color: Drupal must use more than color alone to indicate which fields have errors. This is a major WCAG violation that we didn't solve for Drupal 7.
- Links jump to errors: The $messages area at the top of the page will provide links to jump to errors as WCAG suggests.
- Full error text inline: At the location of each form field, its error text will be presented in full. The markup order will likely put the error message between the field's label and the field itself. The links from the $messages area will jump to the field label first so users can review the label, then the error, then the field where they can fix the submission.
- ARIA described-by: Use ARIA described-by to semantically associate the error message with the field in a machine-readable, assistive technology-friendly way.
Usability considerations
- Improve readability
- "Prevents flooding the top of the page with long error messages" - yoroy
- On small screens and devices, users will be able to find relevant error messages for each field without scrolling up to the top.
Comments
#1
#2
This really is ready to get into core for D8. A sandbox would be useful for this, but mostly we just need some patches to start considering.
Brandon, thanks so much for pushing through with this.
#3
Just in case people have not seen these yet, there are two modules in contrib that attempt to do this.
http://drupal.org/project/inline_messages
http://drupal.org/project/ife
I have not yet tried these out, but they both have D7 branches.
#4
Ok ... here is a first swing at a patch.
There are few things that are not good/not ready for prime-time:
This needs tests, and I'm fairly certain that this will fail some tests...
#5
oops .. uploaded the patch twice instead of the screenshot

#6
This patch fixes the anchor links so that they work in the overlay, but if there are multiple anchor links and you click one of them, then scroll up and click another everything dies.
Not sure how to create those links so that they always ... ya know ... work
#7
The last submitted patch, 1493324.patch, failed testing.
#8
EDIT: ignore the patch in this comment, see #10
This patch should solve many of the test fails (but not all). In addition it puts the css in the correct place and adds the "X" icon to help separate the error message from the title... Still havent figured out a better place to grab the error than the them_form_element(). Must figure that out...
As for the issue with multiple anchor links in the overlay: #1542472: Clicking on multiple anchor links while in overlay causes a page refresh potentially causing form data to be lost
#9
The last submitted patch, 1493324.patch, failed testing.
#10
Oooops .. wrong patch. Lets try this
#11
The last submitted patch, 1493324.patch, failed testing.
#12
Ok .. this patch solves a bunch of the tests locally. Lets see what testbot says
#13
The last submitted patch, 1493324.patch, failed testing.
#14
Here is an update on the current patch and the remaining issues:
The link in the top error message does not work in overlay at presentThere is a bug in overlay when you click an anchor link after you have already clicked one. See #1542472: Clicking on multiple anchor links while in overlay causes a page refresh potentially causing form data to be lostCurrently I am adding "messages" and "error" classes to the form element but that is not correct. Should I add these class definitions to system.css? If not, where?Fixed#15
Here is an update on the current patch and the remaining issues:
The link in the top error message does not work in overlay at presentThere is a bug in overlay when you click an anchor link after you have already clicked one. See #1542472: Clicking on multiple anchor links while in overlay causes a page refresh potentially causing form data to be lostCurrently I am adding "messages" and "error" classes to the form element but that is not correct. Should I add these class definitions to system.css? If not, where?FixedA from that redirects the user on submit even if an error occurs is not handled properly. For an example, try using the search block without entering any keywords. You should be directed to /search/node and see this error: Please enter some keywords. Since we are no longer using drupal_set_message at the time of the error is discovered (via form_set_error) the error is no longer stored in a session early enough.Should be fixed by this patch.#16
A couple fixes for stuff I broke in #15
#17
The last submitted patch, 1493324.patch, failed testing.
#18
Oops, I didn't follow this one. Sorry!
Can anyone tell me why we have a bounding box + icon? I thought the consensus was that we had a signal like "!" or so.
#19
@Bojhan: I added the icon because the error and the title looked confusingly similar
In other news, the current patch has issues with checkboxes/radios ... both the group and the individual form elements get the error state. Wont have time to look until later this week.
#20
These are definitely good patterns. I do wonder if on a code level we should also be looking at adding HTML5′s required attribute as well as ARIA’s "aria-required".
http://www.w3.org/TR/2011/WD-html5-20110525/common-input-element-attribu...
http://www.w3.org/TR/wai-aria/states_and_properties#aria-required
This coming from @feather's articles on required field best practices:
http://simplyaccessible.com/article/required-fields-right/
http://simplyaccessible.com/article/required-form-fields/
And also worth pointing to:
http://www.alistapart.com/articles/aria-and-progressive-enhancement/
#21
@mgifford, My feeling is that we should add both the ARIA and HTML5 markup to indicate required fields. However, I believe that is a separate issue and we should not try to tackle it in this issue. I know the markup for required fields introduces some complexity about the ability to use the "Cancel" or "Previous Step" buttons in multi-step forms, so it should definitely be a separate issue that we address carefully.
#22
Good point. Adding #1623098: Add HTML5 & ARIA for Required Form Elements and also tagging this issue for the sprint.
#23
I clearly have not had a lot of time to try and plow through some of the roadblocks I've come across already ... I still plan on working on this, but I dont want anyone to wait on me if they want to take a swing so I'm unassigning myself
#24
Ok ... I've been looking at this issue again and I'm determined to figure it out. I need some feedback though:
I think that the only to fix for https://skitch.com/bleen/eyhxf/site-information-d8 is to add another FAPI property called "#hide-errors" (or something) and automatically apply that to radio's that are part of radio groups and checkboxes that are part of checkbox groups. This property might be useful anyway, but I'd love to get another opinion.
I dont want to go too far down this rabbit hole only to find out that there are strong objections to adding a new FAPI property.
Thoughts?
#25
Linking to related issue about validation of complex form elements #179932: Required radios/checkboxes are not validated
@bleen18 - are these types of errors all tied to compound forms that probably should be in a fieldset anyways? #504962: Provide accessible labels (was "Use fieldset and legend") for compound form elements
I'd just like to know how to repeat that nasty error you got. Not opposed to the #hide-errors. Something we might be able to talk about on the weekend at the a11y code sprint.
#26
Mgifford: currently these errors are only tied to radios elements and checkboxes elements but I havent tested much with more complex forms yet. Basically it would effect any form elements that share a #name the way the radio element (correctly) shares a name with its parent radios element. Makes sense?
#27
This patch:
Still to do:
Important Notes:
#28
The last submitted patch, 1493324.patch, failed testing.
#29
@bleen18 Thanks for keeping this issue moving, I really love to get this in soon so we can usability test it.
I don't really like that during this thread, we tend to randomly add functionality. It's taken quite a while to reach concencus on some of the fundamental parts, lets get those in first. A quick review;
1 ) Lets lose the icons, per field - I never liked the icon, and it only adds a whole lot of clutter on the page.
2 ) The error should be next to the label, not above.
3) The next/previous is to me, functionality that hasn't been agreed upon - so lets keep that out of the patch.
I honestly, don't see how the fieldset is adding anything. If I am color blind, I have no idea what a "gray" box around a field communicates. As some who can see this color, it adds a whole lot of unnecessary clutter. I thought we just needed some signaling, like a "!" in front of every error.
#30
There's an interesting problem with the Confirm Password field from user.module
When submitting mismatched passwords, the confirm password field is correctly highlighted, but isn't included in the messages area. Here's a screenshot from /admin/people/create. I deliberately chose a username which I knew already existed, and provided mismatched passwords, so there are two errors. The messages area reads: "2 errors have been found: , Username".
The problem is that the confirm password element doesn't have a #title property. Instead, it has two password elements as children, which have their own #title properties. So we need to find a more reliable way to include the field name in the messages area. The test results from comment 16 shows approx. 100 failures from form_display_errors(), so I guess this problem extends to other fields too.
Also note the position of the comma. form_display_errors() isn't listing the error-fields in the same order that the fields appear in the form, which is somewhat confusing.
#31
The links in the error-messages area aren't very easy to use if you're a sighted keyboard-only user.
An example scenario: visit /admin/people/create, and trigger an error by providing a username which is aleady in use (e.g. admin). When the form is returned with errors, try to correct them using only the keyboard...
(This test was using Firefox 13 on Linux + KDE.)
Currently the error-message links use the id attribute of the elements as their href. Using the link changes your place in the tabindex order, but it doesn't actually focus the input.
Suggestions:
Another weird behaviour I sometimes observed: after following the shortcut to the username field, the page shifted in the viewport, and the username input was concealed beneath the toolbar, so even if it did gain focus, you wouldn't be able to see what you were typing.
#32
Re #29:
1 & 2) I'm not married to the icons, but putting the error next to the field labels extremely problematic for long field labels and terribly confusing when the error appears on a non-required field (aka with no "*") offering any kind of separation. Suddenly the field looks like its title & the error message are concatenated into one string. I feel pretty strongly that the error should not appear next to the title for these reasons; I dont feel strongly at all that we need the icon.
3) This issue is about UX. If there is a good usability argument for getting rid of the next/prev links I think we should definitely discuss but just because these links were not in the screenshot in the original is not a good reason to nix them. Think about the UX on a long form:
Thats a terrible UX compared to:
Can we at please keep this open for discussion?
Re #30:
Thanks for taking a swing with this ... I knew there'd still be some problems to deal with.
Anyone have any ideas about this one? Off the top of my head, nothing seems to come to mind.
[edit] I hadnt finished that last sentence before hitting save - DOH!
#33
Well if you really want that kind of link inside error messages, why not a link "return to top" instead of next/previous? You don't have to scroll to the top.
That said prev/next feel way to "invasive" to put by default in core.
#34
re #31: hmmm ... this one is going to suck but definitely needs to be addressed. The biggest challenge I see is that some form elements are groups of elements (ex: radios) and some are not.
Maybe we can add an ID to the error message itself a link to that? Then the tabbing *might* work out more better? Maybe?
#35
I agree with Bohjan. It seems focus gets lost and we are not maintaining focus on the primary issues at hand.
#36
@bleen18: I agree with Bohjan too. Even though I see your argument about the "next" links being helpful to users rather than scrolling, I still feel we should stick to the consensus that was reached. Later improvements can become another issue later if we can build consensus around that.
We have spent since April 2009 on this issue (it started as #447816). Let's please get the part we all agreed on into Drupal 8.
#37
This issue is about improving the accessibility and usability of form errors. I appreciate that there was a lot of work done prior to my getting involved in this issue and I don't mean to minimize that but at the end of the day we all want an improved experience, right? That said, I don't believe there was any consensus around either of these two issues in the wiki for this issue.
1) regarding the position of the error next to the label: Evan Donovan made this comment, http://groups.drupal.org/node/209513#comment-710049, where he made the identical point I am making: the error should be on a separate line. That comment was not discussed or responded to. No consensus was had...
2) the next/prev navigation: there was no consensus around this because it was never discussed. In the wiki the only example of a "very long form" is a form that has only 7 fields. This is minuscule. There was no discussion at all about how this would work with a form that has dozens of fields. I maintain several modules that have forms like this (DFP and Dart for instance) and without the next/prev nav (or some other solution) I would argue that what we have now is more usable (though definitely not as accessible). Disclaimer: both of those modules use v tabs heavily to improve the UX of the large forms but even still there are individual tabs with far more than 7 fields
I understand that there was discussion ahead of time on this issue and I have been involved in several d.o. issues where someone has come along and tried to derail a consensus but I have also been involved in issues like that where someone has come along and derailed the consensus because something important had not been considered. The reason I am being stubborn here (you can look back at other posts of mine and see that I am never stubborn like this) is because it is this exact UX problem that my users suffer and that I want to see fixed (errors on very long forms).
Consensus is good. Consensus is important. But a good consensus should not prevent us from making good adjustments. If you don't think these are good improvements, please make those arguments and I will gladly listen but don't just dismiss them because no one brought them up 4 months ago.
Final note: this is my last plea... If people still think we should just do exactly what is in the original post without any changes at all I will not argue after this. Although I've always though that stepping up and actually bringing the code held more weight in this community...
#38
@bleen18 You are totally right, and I am sorry. The reason why we might respond somewhat harshly, is because its been a really though issue to reach concencus on - that is however no excuse not to respond to your suggestion. From my point of view we have reached concencus on the fact that we need; error links on top, error messages inline and some visual signaling inline that there are errors.
Let me argument, why I think this particular improvement of placing next/prev links isn't good:
1) The functionality if I understand correctly, it is primarily nice to have when there are many errors and when the user is navigating by keyboard. To me both the first and last argument, do not apply to a majority use cases and our audience.
2) It adds controls that are optimized for keyboard users, visual users are going to be far more adapt to scanning the left side - finding the red labels. I find it highly unlikely, one would scroll to the top - to go to the next error.
3) The links as they are now, require some visual boxing - such as a fieldset. I don't think we need a fieldset, therefor it will either require redesign of these elements or make these "hanging in air".
4) Last is the fact that it takes up a lot of screen estate, for something that is not required. If you look at how this could look on mobile, we are getting into quite messy waters.
Again sorry, for not responding on your suggestion initially.
#39
Ok .. these are some discussion points I can work with :). Lets see if we cant go through them and either come to a general agreement why these links should stay, change or go...
1) Yes, you are correct. these links are most useful for a form with several errors. If there is only one error, no links would exist and if there are only two, the first one would only have the "next" and the last would only have the "prev". I agree that in a majority of cases no one would see any of these links in which case we're both happy :) In the rarer case of multiple form errors however, that is when these links are most useful
2) I've tried writing a response to this one a couple of times and so far I have (internally) vehemently agreed with you and vehemently disagreed ... It just feels like if we can make it easier we should. One thing I will say is that if we ultimately decide to nix these next/prev links perhaps we should keep them for keyboard users the way that the "skip to" links work - I'm not quite ready to concede the point yet, but it's worth thinking about.
3) This one I dont understand. You briefly mentioned fieldsets earlier in #29 (I think) and I forgot to ask about it then, but as it stands there are no fieldsets being added anywhere. Can you elaborate.
4) My argument here is (again) it only takes up that extra real estate when it is useful ... and scrolling on a mobile device (an already crappy experience) is exactly the time I think this functionality is most useful.
Does the fact that these nav elements only appear when there are multiple errors help alleviate your concerns? Also, a disclaimer: I barely gave any thought to the positioning/styling of those next/prev links so if there are suggestions on that front that might help to settle this that could work too.
Thanks for talking this out with me ... I'm sure that we'll come to a good conclusion at the end. In the mean time I'll try and spend some time this weekend on the issues raised in #30 & #31 as this is all moot if those bugs dont get squashed.
#40
One other question unrelated to the next/prev debate...
The FAPI property I added is called #hide_errors:
#41
We seem to assume we're going to have a form with lots of errors here, I agree with bojhan that for the typical use-case this is not true.
Showing form validation errors is an UX fail in and of itself. It means there is no client-side validation (HTML5 can do that to some extend) and that the descriptions/labels were confusing, not explicit enough.
While I understand your point bleen18, I think making the HTML5 integration of form validation would be a better way of addressing this issue because if you can reduce the number of errors to begin with, this simplify the problem. When validation error do happen the agreed upon way of dealing with it might not be the best, but it's good enough. What's important is that contrib is still able to tweak it and add prev/next buttons to form errors.
#42
Regarding the question raised in 40, I think we can handle nested elements with logic like this:
foreach ($element in @form) {if (isset($element['parent']['error']) {
// do not give this element the red box and error icon, because the parent will get those
} else {
// this element needs the red box and error icon
}
}
Hopefully with that pseudo-code idea we can do this without introducing a new FAPI #hide_inline_errors property.
#43
Regarding the prev/next links discussed in 38 and 39, my feeling is that they are more harm than help. They add a lot of UI clutter/overwhelm without delivering much help to users. At the top of the page there is a summary of the errors with a link to each erroneous field. Any user who is having trouble finding which fields have errors can return to the top of the page and use those links. Scrolling back to the top of the page is a quick gesture on a trackpad or a 1-finger touch at the top of an iPhone/iPad screen.
@bleen18, I do want to thank you for your passion to make this UI good and your willingness to explain your arguments and work through this decision together.
#44
#42: there is no element[parent][error] ... That would be stupendous though as it would solve this particular issue perfectly.
Re next/prev ... I appreciate that people have started to make some decent arguments against the merits of this functionality (and not just the fact that it is a change) and it seems that most of them make reasonable points against the proposal so I'm going to remove it from my next patch (after some much deserved BBQ).
#45
Ok folks ... I need some guidance:
This patch does 3 things:
#46
Feedback on these first 2 items:
element[parent][error]).Is that feasible?
#47
Requiring title would work great but I like your suggestion of "error in this text field" as a fallback.
As for your point about hide errors...
More feedback welcome.....
#48
+++ b/core/includes/form.inc@@ -902,9 +902,16 @@ function drupal_process_form($form_id, &$form, &$form_state) {
+ // Occassionally a form will set an error in its submit handler so we make
+ // sure to display those errors here before the form is redirected.
+ form_display_errors($form);
We do not babysit broken code, and setting a form validation error after form validation has completed is broken. This can/should be removed.
+++ b/core/includes/form.inc@@ -902,9 +902,16 @@ function drupal_process_form($form_id, &$form, &$form_state) {
+ else {
+ form_display_errors($form);
+ }
1) It looks like this should be moved to the end of drupal_validate_form() instead.
2) We likely want to limit this additional processing to non-programmed forms.
+++ b/core/includes/form.inc@@ -3048,6 +3137,8 @@ function form_process_radios($element) {
+ // Errors should only be shown on the parent radios element.
+ '#hide_errors' => TRUE,
Need to think about this idea some more, but FWIW, I think that this should rather read #error_use_parent or similar. #hide_errors is absolutely misleading.
#49
I'm not sure what you mean by this... can you elaborate?
Are you mulling over the idea of using a property like this? or just the name of the property (which I agree needs changing)? I dont want to keep going too far down this rabbit hole if this solution is ultimately a dead end.
#50
@bleen18 - With form_display_errors($form), why was it added here? Can it be moved up in the processing so that we're not validating it twice?
@sun - any thoughts on @bleen18's response? Just want to get some clarification here. Might make sense to do this on IRC. What's the best way to get feedback from you on this issue?
#51
re: #49:
i) I meant that the specific call to form_display_errors() I referenced should be wrapped in a
if (!$form_state['programmed'])condition.btw, it looks like you can skip the
else, because if the initial if condition is positive, then the call to drupal_redirect_form() will end the request.ii) I meant the name of the #property only.
Overall, I need to spare some time to give this patch some more thought though. However, it would still be a good idea to get these known issues out of the way already.
#52
This patch addresses @sun's comments in #48 and in doing so address @mgiffords comment in #50.
The big issues that still remain include:
#53
oops ... forgot to attach patch
#54
The last submitted patch, 1493324.patch, failed testing.
#55
Looking at @yatil's js code now - https://github.com/yatil/accessible-form-js
Probably not something we can draw on, but interesting model.
#56
@sun ... re: #38
So what should we do in the case of the test that is failing on the search block? In that case, of search_box_form_submit? In that form submit function errors are set but there is no way to pass the test that makes sure the user is redirected if the form is empty if that validation functionality is moved from form submit to a validation function. (http://api.drupal.org/api/drupal/modules%21search%21search.test/function...)
Thoughts?
#57
Could an exception be made for search?
@bleen18 Are there other examples where where we might need form validation done there?
#58
#57 that was the only one i saw, but once I found it I stopped looking. The point here though is that even if we just have one exception, then i would need to put back the code that @sun suggested I remove in #38.
That code would handle all exceptions and it couldn't easily be altered to only handle one or two exceptions if that was the desired functionality.
Basically we are talking all or nothing: we either put in code that handles form_set_errors in a form_submit function, or we dont.
#59
search_box_form_submit() is the exact definition of broken code. ;) I wasn't aware we have that in core. Let's create a separate issue to fix that (but check for a possibly existing first, please).
#60
created #1789768: search_box_form_submit() improperly calls form_set_error()
#61
@sun can this patch proceed on it's own now that there is a separate issue for search_box_form_submit()? Also, I'd like some ideas on how to better tag @bleen18's new patch. Not sure if a WTF tag is the best way to get folks to look at and review this issue.
I'd just like to see that we can't have better inline form error handling in D8 at the moment and want to see that we address these. We could mark it as postponed possibly, but not sure how related it needs to be.
#62
Great to see that there is now a patch to try out #1789768: search_box_form_submit() improperly calls form_set_error() to deal with the search_box_form_submit() issue.
I really think we should be able to keep working on the patch in #53 at the same time though.
#63
+++ b/core/includes/form.inc@@ -955,6 +955,52 @@ function drupal_process_form($form_id, &$form, &$form_state) {
+ return $title;
+++ b/core/includes/form.inc@@ -1641,11 +1689,13 @@ function form_get_errors() {
+ return $form[$key];
+++ b/core/includes/form.inc@@ -1940,6 +1991,39 @@ function form_builder($form_id, &$element, &$form_state) {
+ $element = form_get_element($element_key, $form[$key]);
+ if (!empty($element)) {
+ break;
+ }
Need to use soft-tabs, your editor is inserting tab characters.
#64
This is important to fix, but the bigger issue is that it seems like the whole diff needs to change and no longer applies due to some recent submits.
$ git apply 1493324_9.patch1493324_9.patch:71: tab in indent.
return $title;
1493324_9.patch:119: tab in indent.
return $form[$key];
1493324_9.patch:157: tab in indent.
$element = form_get_element($element_key, $form[$key]);
1493324_9.patch:158: tab in indent.
if (!empty($element)) {
1493324_9.patch:159: tab in indent.
break;
error: patch failed: core/includes/common.inc:6734
error: core/includes/common.inc: patch does not apply
error: patch failed: core/includes/form.inc:865
error: core/includes/form.inc: patch does not apply
I tried to just quickly do an upgrade manually but too much has changed since August 16h when this patch was rolled. Looks like it needs to be rebuilt...
#65
#1789768: search_box_form_submit() improperly calls form_set_error() Kindly needs a careful review, please. =)
#66
Re-rolled against HEAD.
This still needs a lot of work.
#67
The last submitted patch, drupal8.form-error-inline.66.patch, failed testing.
#68
Patch still applies nicely, but there are 17 fail(s) in the tests.
Hard to do the manual testing with - #1797438: HTML5 validation is not fully accessible - as the browser validation gets in the way.
#69
#66: drupal8.form-error-inline.66.patch queued for re-testing.
#70
The last submitted patch, drupal8.form-error-inline.66.patch, failed testing.
#71
re #68: ... to test I used firebug/chrome to remove the "required" attribute from the input manually after the page had loaded. Not ideal, but Drupal doesnt know the difference and it stops HTML5 validation from pestering you
#72
FYI: I created #1845546: Implement validation for the TypedData API to try to solve this on all levels, since there are only 10 days left, we need to figure out what needs to be done before feature freeze and what can be done later.
#73
Can someone re-roll @sun's patch from October? There's more progress now on #1789768: search_box_form_submit() improperly calls form_set_error()
#74
Re-roll
#75
The last submitted patch, drupal8.form-error-inline.74.patch, failed testing.
#76
This should fix at least all the notices.
#77
The last submitted patch, drupal8.form-error-inline.76.patch, failed testing.
#78
#76: drupal8.form-error-inline.76.patch queued for re-testing.
#79
The last submitted patch, drupal8.form-error-inline.76.patch, failed testing.