diff --git a/docs/topics/forms/focus.md b/docs/topics/forms/focus.md index d0ef262c1..39dc1f7d5 100644 --- a/docs/topics/forms/focus.md +++ b/docs/topics/forms/focus.md @@ -1,5 +1,5 @@ --- -title: Focus handling +title: Form focus handling layout: default parent: Web forms nav_order: 6 @@ -7,18 +7,201 @@ nav_order: 6 # Form focus handling -{: .alert } -This content needs to be rewritten and expanded. -Related issue on [GitHub #158 Topic Form focus handling](https://github.com/wpaccessibility/wp-a11y-docs/issues/158). +Keyboard and screen reader users rely on predictable and visible focus behavior to navigate web forms. +Proper focus management ensures that users can efficiently move between fields, understand where they are, and successfully complete tasks. + +--- + +## Why focus handling matters + +Focus is the visible and programmatic indicator of which element on the page is currently active — where keyboard input will go. + +A well-managed focus experience ensures that: + +- Users can tab through form elements in a logical order. +- Focus is always visible and clearly styled. +- Dynamic updates don’t move focus unexpectedly. + +--- ## Consistent tab order -It is a common technique for forms to give the first input field `tabindex="1"`. This can be annoying or confusing for keyboard users, as the tab order does not match what they expect. +### Description + +Tab order determines how users navigate through form controls using the **Tab** key. +Manually setting `tabindex` values can easily break expected navigation flow. + +Avoid using `tabindex` with positive values (`tabindex="1"`, `tabindex="2"`, etc.). +Instead, rely on the natural order of the HTML structure for predictable navigation. + +### Incorrect: Using positive tabindex values + +```html +
+``` + +**Problem:** +The tab order jumps unpredictably between elements, making the form confusing for keyboard users. + +### Correct: Natural tab order + +```html + +``` + +**Best practice:** +Let the browser manage focus order naturally. It follows the logical reading order of the document. + +--- + +## Don't remove native :focus styling + +### Description + +Modern browsers provide strong default focus outlines for focused elements. +These outlines help users track their position on the page as they navigate. + +Removing the outline may make it impossible for sighted keyboard users to know where they are on the page. + +### Incorrect: Removing focus outline -Avoid applying `tabindex` attributes with positive values anywhere on your site, so that the keyboard path through the form is predictable and matches the visual layout of the form. +```css +/* Never do this */ +*:focus { + outline: none; +} -## Don’t remove native :focus styling +button:focus { + outline: 0; +} +``` + +**Problem:** +Keyboard users lose the visual indicator showing which element is currently focused. + +### Correct: Enhance focus styling + +```css +/* Enhance the default outline */ +button:focus { + outline: 2px solid #0073aa; + outline-offset: 2px; +} + +/* Or provide custom focus styles */ +input:focus, +textarea:focus, +select:focus { + border: 2px solid #0073aa; + box-shadow: 0 0 0 2px rgba(0, 115, 170, 0.2); +} +``` + +**Best practice:** +Always provide visible focus indicators. You can enhance or replace the default outline, but never remove it without providing an alternative. + +--- + +## Managing focus programmatically + +### Description + +When content updates dynamically (modals, form validation, AJAX submissions), you may need to manage focus with JavaScript to maintain a logical user experience. + +### When to move focus + +- **Opening a modal:** Move focus to the first interactive element inside the modal. +- **Closing a modal:** Return focus to the element that triggered it. +- **Form errors:** Move focus to the first error message or field. +- **Dynamic content loaded:** Optionally move focus to new content or provide clear indication. + +### Example: Focus management for modal dialogs + +```javascript +// Opening modal +function openModal(modalId) { + const modal = document.getElementById(modalId); + const triggerElement = document.activeElement; // Remember trigger + + modal.style.display = 'block'; + modal.setAttribute('aria-hidden', 'false'); + + // Move focus to first focusable element + const focusable = modal.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'); + if (focusable) { + focusable.focus(); + } + + // Store trigger for later + modal.dataset.trigger = triggerElement.id; +} + +// Closing modal +function closeModal(modalId) { + const modal = document.getElementById(modalId); + const triggerId = modal.dataset.trigger; + + modal.style.display = 'none'; + modal.setAttribute('aria-hidden', 'true'); + + // Return focus to trigger element + if (triggerId) { + document.getElementById(triggerId).focus(); + } +} +``` + +### Example: Focus management for form validation + +```javascript +function validateForm(formElement) { + const errors = []; + const firstNameInput = formElement.querySelector('[name="first"]'); + + if (!firstNameInput.value.trim()) { + errors.push({ + field: firstNameInput, + message: 'First name is required' + }); + } + + if (errors.length > 0) { + // Display error messages + displayErrors(errors); + + // Move focus to first error field + errors[0].field.focus(); + + return false; + } + + return true; +} +``` + +--- + +## Best practices summary + +1. **Natural tab order:** Avoid positive `tabindex` values. Use semantic HTML structure. +2. **Visible focus:** Never remove focus indicators without providing clear alternatives. +3. **Logical focus flow:** Ensure focus moves in a predictable sequence through form elements. +4. **Focus management:** Move focus intentionally when content changes dynamically. +5. **Return focus:** When closing modals or dismissing content, return focus to the trigger element. +6. **Test with keyboard:** Navigate your forms using only the Tab key to verify the experience. + +--- -Most modern browsers have strong default `:focus` styling, making it easy for a user to tab from control to control and see clearly where they are on the page. +## Resources -If you remove this, it is very easy for a sighted user to get lost and abandon the page. Custom `:focus` states are just fine; but avoid subtlety. Focus is an undirected action – meaning that the user does not know in advance where they are going, and will need to locate focus after it moves. Strong states make this easier. +- [WAI: Managing focus](https://www.w3.org/WAI/WCAG21/Techniques/general/G149.html) +- [MDN: :focus CSS pseudo-class](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:focus) +- [WebAIM: Keyboard accessibility](https://webaim.org/techniques/keyboard/) \ No newline at end of file