Manual ARIA injection vs. waiting for native navigation plugin support in Eleventy
0 reputation · 09 May 2020, 00:38 UTC
0 reputation · 09 May 2020, 00:38 UTC
Eleventy's navigation plugin builds hierarchical menus from front‑matter but emits plain <ul>/<li> markup without ARIA landmarks. Teams targeting WCAG 2.1 AA must decide how to add role="navigation" and aria-label to every generated navigation block.
Approach A: author a shortcode or filter that wraps the plugin's output in a <nav> element with the required attributes. This works today but duplicates wrapper logic across layouts and requires developers to remember the pattern on every new template.
Approach B: rely on the data cascade and eleventyComputed to inject ARIA attributes centrally. This reduces repetition but couples accessibility markup to the global data layer, making it harder to override for special cases (e.g., a footer nav that needs a different label).
Neither approach is officially blessed, and the plugin's roadmap has not committed to automatic ARIA injection. The decision affects every page template and the long‑term maintenance burden of accessibility compliance.
For a site that will grow to dozens of distinct navigation regions (header, sidebar, footer, breadcrumb, etc.), a parameterized shortcode or filter that wraps the plugin's output in a <nav aria-label="…"> scales better than relying on the data cascade or eleventyComputed. The wrapper keeps accessibility markup visible in templates, allows each region to set its own label, and can be centralized in one helper file. Waiting for native ARIA support is not recommended because the plugin's roadmap has not committed to it, and any future native implementation would require migration anyway.
A reusable wrapper (Approach A) scales better. Each navigation region calls the same shortcode with a distinct aria-label and optional landmark attributes. This avoids duplicating wrapper logic across layouts while keeping the decision explicit in the template. Central injection via the data cascade (Approach B) reduces repetition but hides accessibility markup from template review and makes special-case labels (e.g., a footer nav needing a different label) harder to override.
Eleventy does not provide an official extension point for the navigation plugin's HTML output. The common pattern is to create a shortcode or filter that receives the plugin's rendered list and returns a wrapped version. This keeps the plugin intact and avoids forking.
The main risk is double-wrapping (e.g., two <nav> elements or duplicate role="navigation"). Mitigate this by making the wrapper conditional: only inject ARIA attributes when they are not already present. Centralize the wrapper so a single change can disable it if native support lands.
<ul>/<li> markup without ARIA landmarks or author-controlled labels.eleventyComputed moves presentation markup into data logic, complicating per-region overrides.<nav>, role="navigation", or aria-label are already present.navWrapper that accepts the navigation HTML, an ariaLabel, and optional role. Return <nav aria-label="{{ ariaLabel }}">{{ content }}</nav>.role="navigation" exists on the root element. Confirm output is not double-wrapped.What version of Eleventy and the @11ty/eleventy-navigation plugin are you using? This determines whether any native ARIA support is already available and changes the urgency of a custom wrapper.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.