DataForm: Stop card and details validation from hijacking focus - #80685
Conversation
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
2 similar comments
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
@mirka should be the best person here to give feedback (I'm currently unable to dedicate much time to Gutenberg work) |
45c7c98 to
144b657
Compare
mirka
left a comment
There was a problem hiding this comment.
I went ahead and added a story to document the pattern, if that's ok 🙏
| * need to report on a recurring event such as losing focus. It returns | ||
| * how many inputs it revealed an error for. | ||
| */ | ||
| export default function useReportValidity( |
There was a problem hiding this comment.
Maybe this should be renamed to something like useRevealValidity since it's no longer tied to reportValidity.
There was a problem hiding this comment.
The rename makes sense, the hook was renamed to useRevealValidity 👍
|
|
||
| ### Bug Fixes | ||
|
|
||
| - Validated form controls: Only move focus to the invalid control for trusted `invalid` events (form submission, `reportValidity()`). Consumers can now dispatch a synthetic `invalid` event to reveal a control's error message without disturbing the user's place in the form ([#80685](https://github.com/WordPress/gutenberg/pull/80685)). |
There was a problem hiding this comment.
I feel like this is an enhancement?
There was a problem hiding this comment.
You are right, it was moved to the enhancements section 👍
| // the badge, so it stays silent. | ||
| const reportedCount = reportValidity(); | ||
| const message = getValidationMessage( validity ); | ||
| if ( reportedCount > 0 && message ) { |
There was a problem hiding this comment.
Should we gate the speak with isOpen?
There was a problem hiding this comment.
Good catch, the gate was added 👍
Validating on every blur inside a card marked the whole card touched and called reportValidity(), which focuses the first invalid input. Tabbing between two fields therefore jumped focus back to an unrelated field. Errors for every field in a card are now revealed once focus leaves the card, matching what validated controls do on their own first blur, and they are revealed by dispatching a synthetic `invalid` event so no focus move happens. ControlWithError only replicates the native focus behavior for trusted events, so form submission still focuses the first error. The details layout gets the same treatment, and both announce the number of fields needing attention, since the errors now appear silently.
Tabbing away from a collapsed card that was edited earlier revealed nothing, yet still announced the error count — which its header already exposes as a description, so screen readers said it twice.
The details layout has no unit tests, so its half of the fix was uncovered. jsdom doesn't reproduce the focus steal for `details` the way it does for cards, so this asserts the reveal rather than claiming to guard focus — the card tests cover the shared mechanism.
0aa5124 to
6f2876b
Compare
That's a great enhancement, thank you! |
|
Thank you a lot @mirka, @ntsekouras for the reviews. |
Fixes #76832
On the card layout, validation runs on every blur inside the card, and
reportValidity()moves focus to the first invalid field. So tabbing from one field to the next sends focus back to an unrelated field, breaking the natural tab sequence.Following the discussion on the issue, this PR shows the errors of all the fields of a card when the card loses focus, instead of on each blur inside it. The errors are shown by dispatching a synthetic
invalidevent, so focus is never moved. Validated controls only replicate the native focus behavior for trusted events, so submitting a form still focuses the first error. The details layout gets the same treatment, and both announce how many fields need attention, given the errors now appear without moving focus.The panel layout shares the same hook, so reopening a touched panel also shows its errors without moving focus.
Videos
Both videos run the same steps on the left and on the right. The title bar, the caption and the red ring around the focused field were added for the recording only.
DataForm Validation story, card layout — focus the Text field and press TAB without editing anything. Before, focus jumps to Password, the first field with errors. After, it goes to the Textarea, as expected.
Download the MP4
Settings > Content Types > Add post type — click the Singular label and press TAB. Before, focus jumps back to Plural label and the whole card turns red. After, focus moves on to Post type key, and only the field that was left shows its error.
Download the MP4
Testing Instructions
Go to http://localhost:50240/?path=/story/dataviews-dataform--validation and set the layout to
card-collapsible.Focus the Text field, press TAB, and verify focus moves to the Textarea instead of to the first field with errors.
Click outside the card and verify every invalid field shows its error and focus stays where you put it.
Collapse the card and verify the badge appears, expand it and verify the errors are still shown.
Then, with the Content Types experiment enabled, go to Settings > Content Types and click "Add post type".
Click the Singular label, press TAB, and verify focus moves to Post type key instead of back to Plural label.
Click outside the card and verify the fields you left show their errors without pulling focus back.
AI usage disclosure: fix and description drafted with AI assistance and reviewed by me.