🔴 Must-fix (validity / a11y)
- Invalid/empty
altattributes and conflictingaria-hidden
There are several <img>s with alt but no value (invalid), or with real alt text and aria-hidden="true" (conflict). Decorative images: alt="" aria-hidden="true". Informative images: provide meaningful alt and remove aria-hidden.
<!-- BAD -->
<img class="usa-banner__icon" src="/themes/custom/usagov/assets/img/icon-dot-gov.svg" alt aria-hidden="true">
<!-- GOOD (decorative) -->
<img class="usa-banner__icon" src="/themes/custom/usagov/assets/img/icon-dot-gov.svg" alt="" aria-hidden="true">
<!-- BAD (conflict) -->
<img aria-hidden="true" class="usa-banner__header-flag" src="/themes/custom/usagov/images/favicon-57.png" alt="U.S. flag">
<!-- GOOD (either make it informative)… -->
<img class="usa-banner__header-flag" src="/themes/custom/usagov/images/favicon-57.png" alt="U.S. flag">
<!-- …or make it decorative) -->
<!-- <img class="usa-banner__header-flag" src="…" alt="" aria-hidden="true"> -->
Also fix other spots with alt but no value:
<img src="/themes/custom/usagov/images/topics/ICONS_Reimagined_Benefits.svg" alt="" height="56">
<img src="/themes/custom/usagov/images/Reimagined_Jump_to_Arrow.svg" alt="">
- Anchor styled as a button has
role="button"
<a> should not carry role="button" unless it truly behaves as one (via JS). Here it’s a normal link, so remove the role.
<a href="/es/" class="usa-button language-link" hreflang="es">Español</a>
- Inline event handlers doing nothing useful
onfocus="this.placeholder" doesn’t change state and can confuse AT. Remove it (and prefer no placeholder on search if a label is present).
<input … type="search" name="query" placeholder="Search all government" autocomplete="off">
🟡 Accessibility & UX polish
- Add meaningful programmatic labels (buttons/icons)
- Mobile/desktop “Close” buttons: keep visible text (you have it) and ensure the icon is decorative:
<button class="usa-nav__close" aria-label="Close menu">
<img src="/themes/custom/usagov/assets/img/usa-icons/close.svg" alt="" aria-hidden="true">
</button>
- The banner disclosure caret SVGs are decorative; add
aria-hidden="true"(you already hide many via CSS):
<svg class="usa-banner_expand_arrow …" aria-hidden="true">…</svg>
- Better search labels
You have SR-only labels (“Search”)—great. Optionally make them more specific:
<label class="usa-sr-only" for="search-field-small">Search all U.S. government</label>
- Improve JSON-LD consistency
Your canonical is https://www.usa.gov/, but both JSON-LD blocks use https://usa.gov/ (no www). Align to canonical:
{
"@context": "https://schema.org",
"@type": "WebSite",
"name": "USA.gov",
"url": "https://www.usa.gov/"
}
…and:
{
"@context": "https://schema.org",
"@type": "Organization",
"url": "https://www.usa.gov/",
"logo": "https://www.usa.gov/themes/custom/usagov/images/Logo_USAGov.png"
}
- Social image alt text (assistive/social tooling)
Add descriptive alt for Open Graph/Twitter images.
<meta property="og:image:alt" content="USAGov logo">
<meta name="twitter:image:alt" content="USAGov logo">
- Give the Spanish switch a language hint
The “Español” link targets Spanish content—add lang to improve AT pronunciation.
<a href="/es/" class="usa-button language-link" hreflang="es" lang="es">Español</a>
⚡ Performance / stability
- Preconnect for site search (you already do script injection)
Slightly reduces latency for the search service:
<link rel="preconnect" href="https://search.usa.gov" crossorigin>
- Explicit HTTPS for third-party script
The Crazy Egg script uses a protocol-relative URL—make it explicit:
<script src="https://script.crazyegg.com/pages/scripts/0007/9651.js" async></script>
- Native lazy-loading for non-critical images
You already use a lazyload class; also add native loading="lazy" to inline <img> where below the fold (e.g., topic icons, footer art).
<img … alt="" loading="lazy">
- Prevent CLS for icon “tiles”
The topic “cards” use .homepage-icon as a background. Ensure those boxes have fixed dimensions/aspect-ratio in CSS (so layout doesn’t shift while background loads):
.homepage-icon {
width: 56px; /* or whatever final size is */
height: 56px;
flex: 0 0 56px;
}
🧭 Semantics / consistency
- USWDS banner icon images
Where you have alt + aria-hidden="true" or alt without a value, normalize as “decorative”:
<img class="usa-banner__icon usa-media-block__img" src="…/icon-https.svg" alt="" aria-hidden="true">
- Improve
<noscript>GTM iframe accessibility (optional)
You already added title="GTM" and sandbox. Consider aria-hidden="true" to keep it out of the virtual buffer:
<noscript>
<iframe title="Analytics loader" aria-hidden="true" sandbox
src="https://www.googletagmanager.com/ns.html?id=GTM-W8LW6DB"
height="0" width="0" style="display:none;visibility:hidden"></iframe>
</noscript>
Quick copy-pastable fixes (bundle)
- Images: replace all
altwithout value →alt=""; removearia-hiddenwhenaltis meaningful. - Español link: drop
role="button", addlang="es". - Search inputs: remove
onfocus="this.placeholder"; keep SR-only labels; optionally clarify label text. - JSON-LD: switch
https://usa.gov/→https://www.usa.gov/. - Open Graph/Twitter: add
og:image:altandtwitter:image:alt. - Preconnect: add
https://search.usa.gov. - CrazyEgg: use
https://URL. - Lazy: add
loading="lazy"to non-critical<img>. - Icon containers: set fixed size (or
aspect-ratio) to avoid CLS.
If you want, I can generate a minimal patch that only touches the affected lines (no structural changes).