audit: comprehensive accessibility, SEO, and semantic HTML remediation across layouts and content#749
Conversation
Signed-off-by: ParthMozarkar <greatparth21@gmail.com>
61884c9 to
b506608
Compare
kristin-kronstain-brown
left a comment
There was a problem hiding this comment.
@ParthMozarkar Could you take a look at the conflicts with main before we review?
Signed-off-by: Parth Mozarkar <greatparth21@gmail.com>
@kristin-kronstain-brown Done..we are good to go !! |
| <div class="dropdown-content rounded-l bg-white dark:bg-gray-900 absolute" style="top: calc(100% + 0.25rem); padding-top: 0.25rem;"> | ||
| <a href="/docs/envoy/latest" class="text-primary-text dark:text-gray-300 px-4 py-3 block hover:text-primary-bg dark:hover:bg-gray-800 dark:hover:text-white text-left">Kgateway (Envoy)</a> | ||
| <a href="https://agentgateway.dev/docs/kubernetes/latest/" class="text-primary-text dark:text-gray-300 px-4 py-3 block hover:text-primary-bg dark:hover:bg-gray-800 dark:hover:text-white text-left">Agentgateway</a> | ||
| <button class="link whitespace-nowrap text-secondary-link" aria-haspopup="true" aria-expanded="false">Docs {{ partial "utils/icon.html" (dict "name" "chevron-down" "attributes" "class='ml-1 mb-0.5 inline w-5 h-5' aria-hidden='true'") }}</button> |
There was a problem hiding this comment.
changed to in nav.html:
The Docs dropdown trigger had its replaced with a to make it a "proper" menu trigger. A button has no href, so keyboard users who tab to it and press Enter no longer navigate to /docs/. They only open the dropdown. If a user presses Tab past the dropdown, /docs/ is now unreachable by keyboard. The original with a dropdown was not semantically wrong — this is a regression.
|
|
||
| <button type="button" aria-label="Menu" class="hamburger-menu -hx-mr-2 hx-rounded hx-p-2 active:hx-bg-gray-400/20 md:hx-hidden"> | ||
| {{- partial "utils/icon.html" (dict "name" "hamburger-menu" "attributes" "height=24") -}} | ||
| <button type="button" aria-label="Toggle navigation menu" aria-expanded="false" aria-controls="mobile-nav" class="hamburger-menu -hx-mr-2 hx-rounded hx-p-2 active:hx-bg-gray-400/20 md:hx-hidden"> |
There was a problem hiding this comment.
Broken aria-controls="mobile-nav" in navbar.html
The hamburger button now has aria-controls="mobile-nav", but no element in the template has id="mobile-nav". A broken aria-controls reference is worse than omitting the attribute: screen readers announce a control relationship that doesn't resolve to anything.
| {{ if and $versions $version }} | ||
| <div class="dropdown px-2 cursor-pointer"> | ||
| <button class="btn" type="button"> | ||
| <button class="btn" type="button" aria-haspopup="listbox" aria-expanded="false" aria-label="Select documentation version"> |
There was a problem hiding this comment.
aria-haspopup="listbox" + role="listbox" without role="option" on children
The version selector uses aria-haspopup="listbox" on the button and role="listbox" on the
- . A valid listbox pattern requires the
- children to have role="option". The navbar-version.html partial (which renders those children) was not modified in this PR, so the child roles are missing. This produces an invalid ARIA pattern that most screen readers will handle worse than the original.
|
|
||
| <div class="nav-container hx-sticky hx-top-0 hx-z-20 hx-w-full hx-bg-transparent print:hx-hidden"> | ||
| <a href="#main-content" class="skip-to-content">Skip to main content</a> | ||
| <div class="nav-container hx-sticky hx-top-0 hx-z-20 hx-w-full hx-bg-transparent print:hx-hidden" role="banner"> |
There was a problem hiding this comment.
role="banner" on a
The outer wrapper
| {{ if .visible }} | ||
| <div class="bg-[#151927] w-full font-secondary text-sm lg:text-base text-[#DDDFED] text-center inline-flex items-center justify-center leading-7 min-h-4"> | ||
| <a class="p-4" href="{{ .link }}" target="_blank" rel="noreferrer" class="hover:underline"> | ||
| <div class="bg-[#151927] w-full font-secondary text-sm lg:text-base text-[#DDDFED] text-center inline-flex items-center justify-center leading-7 min-h-4" role="status" aria-label="Announcement"> |
There was a problem hiding this comment.
role="status" on the announcement banner
role="status" is a live region for dynamically-updated status messages (e.g., "Form saved"). A static marketing banner is not a live region. Screen readers will treat this as a polite announcement region and may re-announce it on page updates. The role should be removed entirely.
| short: "Delegate authorization decisions to an external service via an Envoy extension." | ||
|
|
||
|
|
||
| long: "External Authorization allows Kgateway to offload authentication and authorization decisions to a dedicated external service. This enables complex, custom security logic that can be shared across multiple applications and services." |
There was a problem hiding this comment.
kgateway should always be lowercased unless it is used at the beginning of a sentence. Needs fixed all throughout.
| short: "Agent-to-Agent Protocol for secure, policy-driven communication across agents." | ||
|
|
||
|
|
||
| long: "The Agent-to-Agent (A2A) protocol defines how autonomous AI agents discover each other, negotiate capabilities, and collaborate on complex tasks. Kgateway facilitates A2A communication by providing secure, policy-driven routing and observability for agentic interactions across different environments." |
There was a problem hiding this comment.
A2A is agentgateway's protocol, not kgateway's. kgateway handles HTTP/gRPC routing; A2A is specific to agentgateway.
This should be removed from kgateway and added to agentgateway docs, if necessary.
| short: "Envoy- or agentgateway-based data plane process that terminates and forwards traffic." | ||
|
|
||
|
|
||
| long: "A proxy is a service that acts as an intermediary for requests from clients seeking resources from other servers. In Kgateway, the proxy (Envoy or Agentgateway) is the component that actually handles the network traffic, applying policies and routing requests to the correct backends." |
There was a problem hiding this comment.
Remove all agentgateway references unless pointing to something in the agentgateway docs.
| } | ||
|
|
||
| /* Skip to content link - visually hidden until focused */ | ||
| .skip-to-content { |
There was a problem hiding this comment.
nav.html (marketing pages) each inject their own skip link and .skip-to-content CSS. They're used in different contexts so they won't normally collide, but if both ever fire on the same page there will be two skip links and conflicting CSS definitions.
| <figcaption class="flex gap-5"> | ||
| {{ if .avatarPath }} | ||
| <div class="w-[3.61819rem] h-[3.69594rem] bg-primary-bg bg-[url({{ .avatarPath }})] bg-cover bg-no-repeat rounded-full"></div> | ||
| <div class="w-[3.61819rem] h-[3.69594rem] bg-primary-bg bg-[url({{ .avatarPath }})] bg-cover bg-no-repeat rounded-full" role="img" aria-label="{{ .name | default "Avatar" }}"></div> |
There was a problem hiding this comment.
The avatar
What this PR does
Performs a comprehensive audit and remediation of accessibility (a11y), SEO, and semantic HTML across all Hugo layout templates, shortcodes, partials, and key content pages for the kgateway.dev documentation site.
Closes #747
Why
The site currently has systemic accessibility gaps that prevent WCAG 2.1 AA compliance, missing SEO metadata that hurts discoverability, and inconsistent use of semantic HTML that impacts both screen reader users and search engine crawlers.
Changes
Accessibility (a11y)
Layout Partials:
layouts/partials/navbar.html:aria-expanded,aria-haspopup, andaria-labelto the dropdown trigger:focus-withinCSS alongside:hoverfor keyboard-accessible dropdownsrole="menu"androle="menuitem"to dropdown itemslayouts/partials/sidebar.html:aria-current="page"to active sidebar linksrole="navigation"with descriptivearia-label="Documentation sidebar"aria-expandedto collapsible section toggleslayouts/partials/toc.html:<nav aria-label="Table of Contents">aria-currenttracking for scroll-spy active headinglayouts/partials/footer.html:<div>with semantic<footer>element<nav aria-label="...">elementslayouts/partials/breadcrumb.html:<nav aria-label="Breadcrumb"><ol>list witharia-current="page"on final itemlayouts/partials/announcement.html:role="status"for non-intrusive announcementslayouts/404.html:<main>wrapper and proper heading hierarchyShortcodes:
card.html: Ensuredalttext propagation, proper heading level contextcommunity-quotes.html: Used<figure>+<blockquote>withciteattributeintegrations.html: Addedalttext to all integration logoslabs-list.html: Proper<ul>semantics with descriptive link textlearning-paths-list.html: Structured list with accessible descriptionsopenapi.html: Addedtitleattribute to iframe containersvideos-list.html: Addedtitleattributes to video embedsSEO
New file:
layouts/partials/custom/head.htmlog:title,og:description,og:image,og:url,og:type)twitter:card,twitter:title,twitter:description)<link rel="canonical">TechArticleandBreadcrumbListschemaslayouts/robots.txt:Sitemap:directiveSemantic HTML
<div>wrappers with<nav>,<main>,<article>,<section>,<aside>across all layout templates_index.mdfiles (~25 files)Content Fixes
content/docs/envoy/latest/security/_index.md: Removed commented-out HTML on line 27data/glossary.yaml: Addedlongdescriptions for all 25 glossary terms (previously all empty)Impact
_index.mdTesting
hugo --minifybuilds cleanly with no errorsmake links)Screenshots
Checklist