carshake.online: accessible names for 118 pages of email fields - #3
carshake.online: accessible names for 118 pages of email fields#3kindrat86 wants to merge 1 commit into
Conversation
118 pages carried an email input whose only description was a placeholder. A placeholder is not a label: it disappears the moment the field has a value, and it is not reliably exposed as an accessible name. Screen readers announced a required unnamed edit box; agents had nothing to key on. Two form shapes were in play. The site-wide capture form already had a name and a correct action/method pair and needed only aria-label and autocomplete. The lead-magnet form (class cs-email-input) additionally had no name at all; its action is javascript:void(0), so adding a name cannot leak over GET, and its handler calls preventDefault. The four localised pages get the phrase in their own language rather than an English one — an English aria-label on a Portuguese page is noise, not a label. Matched against each page's own <html lang>. Two things this repo taught the tooling. It contains another agent's git worktree under .claude/worktrees/, which is git-excluded, so edits made there never appear in git status — the first pass silently modified 114 files on someone else's branch. Those were reverted and the fix scripts now refuse to walk into .claude, .vercel, dist, .next and node_modules. .vercel/output/ is a gitignored prebuilt artifact that had been partly touched; it was made internally consistent, but it should be regenerated before any `vercel deploy --prebuilt`. Verification note: this site's JS behaves differently off its production origin, so a local rendered-side audit is not representative here — /blog and /city/new-york render LESS content locally than in production. The no-JS side does match production almost exactly, and that is where these attributes live, so the fix is confirmed in the served documents rather than by a local rendered diff. Re-audit production after deploy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Correction to this PR's description, and an incident to record. The "JS behaves differently off the production origin" claim was wrongThe PR says local and production audits disagreed because this site's JS behaves differently off its production origin. That was the wrong explanation. The ratios varied between runs of the same production URL — 0.476, 1.000 and 2.583 for The auditor now carries a check (A4) that loads each page twice and reports when the two disagree by more than 5%, taking the larger sample so an under-measured render cannot inflate An edit of mine was briefly liveWhile making Current state is correct — production, The general rule stands and is now in the portfolio notes: on any site with a Still trueEverything in the PR body about the actual fix — 118 pages with placeholder-only email fields, the localised |
Sixth site in the portfolio DOM and agent-readability pass. Do not merge without review.
What this fixes
118 pages carried an email input whose only description was a placeholder. A placeholder is not a label — it disappears the moment the field has a value, and it is not reliably exposed as an accessible name. Screen readers announced a required unnamed edit box; agents had nothing to key on.
Two form shapes:
name="email"and a correctaction="/api/email-capture" method="post"pair. Needed onlyaria-labelandautocomplete.class="cs-email-input") — additionally had nonameat all. Its action isjavascript:void(0)so adding a name cannot leak over GET, and its handler callspreventDefault().The honeypot on the site-wide form is already correctly marked (
aria-hidden="true"+tabindex="-1"+ offscreen) and was left alone.Localised pages get their own language
/fr,/es,/ptand/idget the phrase in their own language, matched against each page's<html lang>. An Englisharia-labelon a Portuguese page is noise, not a label.Measured
nameThis site's JS behaves differently off its production origin, so a local rendered-side audit is not representative here. Locally
/blogand/city/new-yorkrender less content than they do in production (ratio >1), and/pricingrenders more. I do not have an explanation for that and did not chase it, but it means local rendered numbers for this site should not be trusted.What is trustworthy: the no-JS side matches production almost exactly (
/pricing1142 vs 1142 chars,/8206 vs 8235), and that is where these attributes live. The fix is confirmed present in the served documents. Please re-audit production after deploy rather than relying on the local numbers.That divergence is itself worth someone looking at — it may be a real defect.
Two things this repo taught the tooling
It contains another agent's git worktree under
.claude/worktrees/, which is git-excluded — so edits made there never appear ingit status. The first pass silently modified 114 files on someone else's branch. Those were reverted, and the fix scripts now refuse to walk into.claude,.vercel,dist,.nextandnode_modules..vercel/output/is a gitignored prebuilt artifact that had been partly touched. It was made internally consistent rather than left half-updated, but it should be regenerated before anyvercel deploy --prebuilt.Deliberately NOT changed
action="javascript:void(0)"on the lead-magnet form — a CSP hazard and meaningless as an action, but changing it risks a real navigation if any handler does notpreventDefault. Worth a separate look.<main>/<header>missing on/free/instant-proof(4 findings) — template change.<a>with no href on/free/instant-proof(C1).color-contrastandregion(12 findings).🤖 Generated with Claude Code