Clear page structure and predictable navigation help people understand where they are, find content, and move through a site. Drupal provides accessible defaults, but themes and modules can weaken them by changing templates, markup, CSS, or JavaScript.
Use this guidance when creating or reviewing a theme. Test the rendered page, not only the Twig template.
Use HTML elements according to their purpose. Semantic HTML gives browsers and assistive technologies useful information without additional code.
nav for major navigation regions.main element for the page's main content.header, footer, and aside where their meanings apply.Prefer native HTML over ARIA. Add ARIA only when HTML does not provide the required semantics or state. Do not add a redundant role to a native element unless testing demonstrates a specific compatibility need.
When overriding a Drupal Twig template, preserve the template's attributes variables and other attributes added by Drupal. Removing them can discard identifiers, classes, language information, ARIA attributes, or JavaScript behavior supplied by core or a module.
Each page needs a concise, descriptive, and reasonably unique title. Drupal assembles this through the head_title variable in html.html.twig. Keep the most specific part of the title easy to identify.
Drupal adds the page language to the html element. Mark passages in another language when correct pronunciation or interpretation depends on it. Do not remove html_attributes when overriding html.html.twig.
HTML regions help screen reader users move directly to major parts of a page. A typical page may include a site header, one or more navigation regions, the main content, complementary content, and a footer.
main element for content unique to the page.nav for major groups of navigation links, not every group of links.aria-label or aria-labelledby.Landmarks do not replace headings or a skip link. They provide another way to navigate the page.
Headings describe the page's organization. Their text should identify the section that follows. Choose heading levels from the document structure, not from the desired visual size.
WCAG does not require exactly one h1, and a skipped heading level is not automatically a WCAG failure. The goal is a structure that people can understand and use. Do not add visually hidden headings by default to compensate for unclear landmarks. Add them when they provide a useful name or structure.
A skip link lets keyboard users bypass repeated content and move to the main content. Drupal 11 core includes a translated skip link in html.html.twig:
<a href="#main-content" class="visually-hidden focusable">
{{ 'Skip to main content'|t }}
</a>
The default page.html.twig provides its target inside the main element:
<main>
<a id="main-content" tabindex="-1"></a>{# link is in html.html.twig #}
...
</main>
If a theme overrides either template, preserve both parts or provide equivalent behavior. The link must be one of the first focusable elements. Its destination must exist on every page. The focusable class makes Drupal's visually hidden link visible when it receives keyboard focus.
Test that activating the link moves focus and the viewport to the main content. The destination must not be hidden behind a sticky header. Do not replace the current pattern with a named anchor, an empty link, custom off-screen positioning copied from old documentation, or text hidden by matching its color to the background.
Navigation should remain consistent and usable with a keyboard, touch, speech input, magnification, and screen readers.
aria-current="page".tabindex to force focus order.An ordinary website navigation list is not an application menu. Do not add role="menu", role="menuitem", or desktop-application keyboard behavior unless the component actually implements the complete ARIA menu pattern.
For expandable navigation, use a button to control each disclosure. Communicate its state with aria-expanded and associate it with the controlled content when practical. If a top-level item must both navigate and expand a submenu, provide separate link and button controls. Make the collapsed and expanded states understandable at every supported breakpoint.
Link text should describe the destination or purpose in its surrounding context. Avoid using a title attribute to repair vague text because it is not consistently available to all users.
The source order should make sense without CSS. Visual order, reading order, and keyboard focus order should describe the same sequence. Be especially careful when using CSS Grid, Flexbox, absolute positioning, or breakpoint-specific layouts to reorder content.
At high zoom and narrow viewport widths, content should reflow without losing information or controls. If navigation changes into a disclosure or drawer, test opening, closing, focus movement, focus visibility, and return of focus. Do not remove important navigation at a breakpoint without an equivalent way to reach it.
Keyboard focus must be clearly visible and must not be entirely hidden by sticky headers, dialogs, or other author-created content. Do not remove the browser focus indicator unless it is replaced with a visible alternative.
Use a table only when rows and columns have relationships. Provide a concise caption when it helps identify the table. Mark header cells with th and use scope for simple row or column headers. For a complex table, simplify it where possible. If it must remain complex, associate data cells with their headers using appropriate markup and test the result with a screen reader.
Do not use the obsolete summary attribute. Put essential context in a visible caption or nearby text. When a table needs horizontal scrolling at narrow widths, preserve the header relationships and make sure keyboard users can reach any interactive content. Avoid making a non-interactive wrapper a tab stop without a demonstrated need.
Automated tools can detect some markup and attribute errors. They cannot determine whether the structure is understandable or whether the navigation works in every state.