Requires that a focused component is not entirely hidden by author-created content such as sticky headers, banners or widgets.
A sticky header, a cookie banner or a chat widget can cover the element that has keyboard focus. The user presses Tab and focus moves, but the focused element is hidden behind a fixed bar. They cannot see what they are about to activate.
This criterion, new in WCAG 2.2, requires that when a user interface component receives keyboard focus, the component is not entirely hidden due to author-created content. Partial overlap is allowed at this level, but should be kept to a minimum.
scroll-padding so that focused elements scroll clear of sticky bars (C43). A sticky header or footer that completely hides focused elements is a failure (F110).Keyboard-only and switch users, who need to see the element they are about to activate. People with low vision who use magnification and have a small view of the page. People who use screen magnifiers and need to keep focus on screen. People with cognitive disabilities who use focus to keep their place.
The European Accessibility Act (Directive (EU) 2019/882) applies to in-scope products and services placed on the market after 28 June 2025. Recital 47 names four principles for websites and mobile applications: perceivable, operable, understandable and robust. Keeping focus in view is part of "operable".
The technical counterpart is the standard EN 301 549, which incorporates WCAG 2.4.11 by reference and turns it into separate clauses for each kind of ICT.
| Clause | Type of ICT | What it requires |
|---|---|---|
| 9.2.4.11 | Web pages | Web content must satisfy WCAG success criterion 2.4.11. |
Because this criterion is new, check clauses 10 and 11 of V4.1.1 for the rows that apply to documents and software. Clause numbers follow the "9. + WCAG number" pattern of EN 301 549. In V3.2.1 the software clause is divided into further subclauses for open and closed functionality. Check the exact numbers in the standard when you cite them.
Standard version: Criterion 2.4.11 is new in WCAG 2.2, so it is not part of EN 301 549 V3.2.1, which is based on WCAG 2.1. It appears in EN 301 549 V4.1.1 (September 2026), the first version prepared specifically for the EAA. V4.1.1 has not yet been cited in the Official Journal of the European Union, so for now it is best treated as a voluntary technical route to the EAA's requirements. Once cited, it will give a presumption of conformity. It is a Level AA criterion.
A note on EAA scope: Article 2(4) of the Directive excludes certain content from the requirements, for example office file formats published before 28 June 2025 and archives that are not updated after that date. Content you publish or change after that date is not covered by these exclusions.
Directive (EU) 2019/882, EUR-Lex, opens in a new tab
When Tab moves focus below a fixed header, the browser may scroll the element only to the top edge, where the header hides it. Add scroll padding equal to the header height (C43).
.site-header { position: sticky; top: 0; height: 72px; }.site-header { position: sticky; top: 0; height: 72px; }
html { scroll-padding-top: 88px; } /* header height plus a gap */Do the same for fixed bars at the bottom.
.sticky-cta { position: fixed; bottom: 0; height: 64px; }.sticky-cta { position: fixed; bottom: 0; height: 64px; }
html { scroll-padding-bottom: 80px; }A banner that covers the page must not hide the focused element. Make it a modal that takes focus, or give the page enough padding.
.cookie-banner { position: fixed; inset: auto 0 0 0; } /* covers focused links */<div role="dialog" aria-modal="true" aria-labelledby="ck" class="cookie-banner">
<h2 id="ck">Cookies</h2>
<button>Accept</button> <button>Reject</button>
</div>
<!-- Focus moves into the banner and the page behind is inert -->A button fixed to a corner can cover content. Leave room, or let users move it.
.chat { position: fixed; right: 0; bottom: 0; width: 320px; height: 400px; }.chat { position: fixed; right: 1rem; bottom: 1rem; }
.chat[hidden] { display: none; } /* closed by default; opens on request */A panel the user opens may overlap content if they can close it with Escape without losing focus.
<div class="panel">…</div> <!-- no way to close it -->panel.addEventListener("keydown", e => {
if (e.key === "Escape") { panel.hidden = true; trigger.focus(); }
});If a script manages scrolling, make sure the focused element ends up clear of any fixed bar.
el.focus({ preventScroll: true }); // stays under the headerel.focus();
el.scrollIntoView({ block: "center" });On mobile, the on-screen keyboard, a bottom bar or a floating button can cover a focused field. Make sure the focused field stays in view.
import SwiftUI
struct CommentForm: View {
@FocusState private var focusedField: Field?
enum Field: Hashable { case name, comment }
@State private var name = ""
@State private var comment = ""
var body: some View {
ScrollViewReader { proxy in
ScrollView {
VStack(spacing: 16) {
TextField("Name", text: $name)
.id(Field.name)
.focused($focusedField, equals: .name)
TextEditor(text: $comment)
.id(Field.comment)
.frame(height: 120)
.focused($focusedField, equals: .comment)
}
.padding()
}
// Scroll the focused field clear of the keyboard and bars
.onChange(of: focusedField) { field in
if let field { withAnimation { proxy.scrollTo(field, anchor: .center) } }
}
}
}
}import androidx.compose.foundation.layout.*
import androidx.compose.foundation.relocation.BringIntoViewRequester
import androidx.compose.foundation.relocation.bringIntoViewRequester
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.OutlinedTextField
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.onFocusChanged
import kotlinx.coroutines.launch
@OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class)
@Composable
fun CommentForm() {
var comment by remember { mutableStateOf("") }
val requester = remember { BringIntoViewRequester() }
val scope = rememberCoroutineScope()
Column(
Modifier.verticalScroll(rememberScrollState()).imePadding() // keep clear of the keyboard
) {
OutlinedTextField(
value = comment,
onValueChange = { comment = it },
modifier = Modifier
.bringIntoViewRequester(requester)
.onFocusChanged { if (it.isFocused) scope.launch { requester.bringIntoView() } }
)
}
}position: sticky and position: fixed elements and whether scroll-padding is set.preventScroll carelessly: Focus moves but the page does not scroll.