a11y: exported semantics (forms/rating/nav/iframe/icons)

- InputField/TextareaField/ContactForm: every control gets a
  deterministic id (slugId() in utils/escape.ts, derived from the
  field's name/label + index for ContactForm's looped fields -- no
  Math.random) with a matching <label for=>; fields with no visible
  label get an aria-label from the placeholder/name instead.
- StarRating: wrapped in role="img" aria-label="Rating: N out of M",
  individual star glyphs marked aria-hidden.
- Navbar: the mobile hamburger toggle gets aria-label="Toggle
  navigation menu", aria-controls="navbar-links", and aria-expanded
  wired to flip true/false in the inline onclick handler.
- VideoBlock and MapEmbed: every exported <iframe> gets a title
  (generic "Embedded video", or "Map of {address}" for MapEmbed).
- Decorative Font Awesome icons (ContentSlider arrows already covered
  in the prior commit; SocialLinks, SearchBar, Testimonials stars) are
  aria-hidden; SocialLinks' icon-only links get an aria-label naming
  the platform alongside the existing title tooltip.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-12 14:19:01 -07:00
parent 9b532e36e8
commit 9969adca72
21 changed files with 255 additions and 27 deletions
+5 -1
View File
@@ -204,7 +204,11 @@ SocialLinks.craft = {
if (hasBg) {
aStyle += `;${getShapeStr()}`;
}
return `<a href="${escapeAttr(safeUrl(link.url || '#'))}" target="_blank" rel="noopener noreferrer" title="${escapeAttr(title)}" style="${aStyle}"><i class="fa ${escapeAttr(iconClass)}" style="font-size:${iconSize}"></i></a>`;
// The link's only content is the icon glyph, so the glyph itself is
// aria-hidden and the accessible name lives on the link (aria-label,
// mirroring the existing `title` tooltip since title support in
// screen readers is inconsistent).
return `<a href="${escapeAttr(safeUrl(link.url || '#'))}" target="_blank" rel="noopener noreferrer" title="${escapeAttr(title)}" aria-label="${escapeAttr(title)}" style="${aStyle}"><i class="fa ${escapeAttr(iconClass)}" style="font-size:${iconSize}" aria-hidden="true"></i></a>`;
}).join('\n ');
return {