CoolFace
Apppublic

getreadystack/accessibility-statement-lint

sourceHugging Facemitupdated 4d agoView on Hugging Face
0likes
index.html262 linesDownload Raw Back to root
1<!doctype html>2<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width,initial-scale=1">6<title>Accessibility Statement Lint (EU model) — free online check</title>7<style>8:root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512}9.wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px}10textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box}11.bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer}12input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px}13table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65}14.sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600}15.note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa}16</style>17<script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script>18<!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/accessibility-statement-lint"></head>19<body>20<div class="wrap">21<h1>Accessibility Statement Lint (EU model)</h1>22<p class="lede">Lints a published accessibility statement against the EU model statement: compliance-status wording, non-accessible content with reasons, preparation and last-review dates, feedback and enforcement sections. Runs entirely in your browser — nothing is uploaded.</p>23<textarea id="src" spellcheck="false"># Accessibility Statement24 25[insert your organisation name] is committed to making its digital services accessible to26everyone, in line with current national accessibility legislation and with good practice27in the sector.28 29This statement applies to the website at https://www.example-agency.test/ and was produced30as part of our quality programme.31 32## Compliance status33 34This website is partially compliant with EN 301 549 V2.1.2. Some sections of the site are35not compliant and work to fix them is ongoing.36 37## Non-accessible content38 39- Older PDF documents in the publications library are not tagged.40- Video recordings of public meetings do not carry captions. Adding captions to the full41  back catalogue would be a disproportionate burden for a team of our size, so the back42  catalogue stays as it is for now.43- Some form fields are missing labels.44 45## Preparation of this statement46 47This statement was prepared on 3 June 2024 following a third-party review of the site.48 49Last reviewed: 12 March 2024.50 51## Feedback52 53If you find a problem, write to webteam@example-agency.test and we will look into it.</textarea>54<div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div>55<div id="out" aria-live="polite"></div>56<div id="paid"><strong>Free here:</strong> Check the accessibility statement open in the editor and name every missing section. <strong>In the editor:</strong> Sweep every locale and sub-site statement in the workspace and write one dated report with a per-file verdict you can hand to the monitoring body — that part asks for a licence key.</div>57<p class="note">Same engine as the VS Code extension, byte for byte.</p>58</div>59<script>var ASTMT_RULES = [60  {"id":"scope_commitment","sev":"high","kind":"require","pat":"is committed to making","flags":"i",61   "msg":"No commitment sentence. The EU model statement opens by naming the body and stating it is committed to making the site accessible."},62  {"id":"law_cited","sev":"high","kind":"require","pat":"2016/2102|Web Accessibility Directive|2019/882|European Accessibility Act","flags":"i",63   "msg":"No legal basis cited. Name Directive (EU) 2016/2102 (or its national transposition), or Directive (EU) 2019/882 for a private-sector service."},64  {"id":"scope_named","sev":"med","kind":"require","pat":"(applies to|covers)[^\\n]{0,80}(website|web site|app|application|service)|https?://","flags":"i",65   "msg":"The statement never says which website, app or service it covers. One statement per covered site is the model's unit."},66  {"id":"compliance_status","sev":"high","kind":"require","pat":"(fully|partially|not) compliant","flags":"i",67   "msg":"No compliance status. The model allows exactly three wordings: fully compliant, partially compliant, or not compliant."},68  {"id":"status_single","sev":"high","kind":"exclusive","alts":["fully compliant","partially compliant","not compliant"],"flags":"i",69   "msg":"Two different compliance statuses appear in one statement. A monitoring body reads the status as a single declared value."},70  {"id":"standard_cited","sev":"high","kind":"require","pat":"EN 301\\s?549","flags":"i",71   "msg":"EN 301 549 is not named. The status has to be measured against the harmonised standard, not against WCAG alone."},72  {"id":"standard_version_stale","sev":"med","kind":"forbid","pat":"EN 301\\s?549[ ,]*(V|version )?(1\\.|2\\.|3\\.1)","flags":"i",73   "msg":"An EN 301 549 version older than V3.2.1 is cited. V3.2.1 is the version listed in the Official Journal for the Web Accessibility Directive."},74  {"id":"nonaccessible_section","sev":"high","kind":"require","when":"partially compliant|not compliant","pat":"non-?accessible content","flags":"i",75   "msg":"Status is partially or not compliant, but there is no Non-accessible content section. That section is what makes the status verifiable."},76  {"id":"reason_category","sev":"high","kind":"require","when":"non-?accessible content","pat":"non-?compliance|disproportionate burden|not within the scope","flags":"i",77   "msg":"Non-accessible content is listed with no reason category. The model has exactly three: non-compliance, disproportionate burden, and content outside the scope of the legislation."},78  {"id":"burden_assessment","sev":"high","kind":"require","when":"disproportionate burden","pat":"assessment","flags":"i",79   "msg":"Disproportionate burden is claimed with no assessment behind it. Article 5 of Directive (EU) 2016/2102 allows the claim only after an assessment of the burden."},80  {"id":"burden_alternative","sev":"high","kind":"require","when":"disproportionate burden","pat":"accessible alternative|alternative format|alternative is available","flags":"i",81   "msg":"Disproportionate burden is claimed with no accessible alternative offered for the excluded content."},82  {"id":"prepared_date","sev":"high","kind":"date_present","label":"prepar(ed|ation)","flags":"i",83   "msg":"No date of preparation. The model requires the date the statement was prepared or last fully revised."},84  {"id":"prepared_date_future","sev":"med","kind":"date_future","label":"prepar(ed|ation)","flags":"i",85   "msg":"The date of preparation is in the future, so the statement cannot have been prepared yet."},86  {"id":"method_named","sev":"med","kind":"require","when":"prepar(ed|ation)","pat":"self[- ]assessment|third[- ]party|external (audit|evaluation|review)|expert (review|evaluation)","flags":"i",87   "msg":"The preparation method is missing. Say whether this was a self-assessment or an evaluation by a third party."},88  {"id":"review_date","sev":"high","kind":"date_present","label":"last review(ed)?|reviewed on","flags":"i",89   "msg":"No date of last review. The statement has to carry the date it was last checked, separate from the date it was written."},90  {"id":"review_stale","sev":"high","kind":"date_max_age","label":"last review(ed)?|reviewed on","months":12,"flags":"i",91   "msg":"The last review is more than 12 months old. Directive (EU) 2016/2102 Article 7(1) requires the statement to be kept up to date, and monitoring bodies sample by date."},92  {"id":"feedback_contact","sev":"high","kind":"require","pat":"mailto:|[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}|feedback form|contact form","flags":"i",93   "msg":"No feedback mechanism. A reader must be able to report an accessibility barrier and request content in an accessible form."},94  {"id":"enforcement_procedure","sev":"high","kind":"require","pat":"enforcement (procedure|body)|ombud|complaint","flags":"i",95   "msg":"No enforcement procedure. The statement must point to the body a reader can escalate to when the feedback goes unanswered."},96  {"id":"placeholder_left","sev":"high","kind":"forbid","pat":"\\[(insert|name of|your |organisation|organization|url|date|add )[^\\]]{0,60}\\]|XX/XX|\\bTBD\\b|lorem ipsum","flags":"i",97   "msg":"A template placeholder was never filled in. This is the most common defect in generated statements and it is visible to the public."}98]99;</script>100<script>// Accessibility Statement Lint — one brain, used by the extension and by the one-page web tool.101'use strict';102var RULES = (typeof module !== 'undefined' && module.exports)103  ? require('./rules.json')104  : (typeof window !== 'undefined' ? window.ASTMT_RULES : []);105 106var MONTHS = ['january','february','march','april','may','june','july','august','september',107              'october','november','december'];108 109function lineOf(text, index) {110  return text.slice(0, index).split('\n').length;111}112 113// "2026-09-16" | "16 September 2026" | "September 16, 2026" | "16/09/2026" | "16.09.2026"114function findDate(line) {115  var m = line.match(/(\d{4})-(\d{2})-(\d{2})/);116  if (m) return { y: +m[1], m: +m[2], d: +m[3] };117  m = line.match(/(\d{1,2})[ .]+([A-Za-z]{3,9})[ ,.]+(\d{4})/);118  if (m) {119    var i = MONTHS.indexOf(m[2].toLowerCase());120    if (i < 0) i = MONTHS.map(function (x) { return x.slice(0, 3); }).indexOf(m[2].toLowerCase().slice(0, 3));121    if (i >= 0) return { y: +m[3], m: i + 1, d: +m[1] };122  }123  m = line.match(/([A-Za-z]{3,9})[ ]+(\d{1,2})[ ,]+(\d{4})/);124  if (m) {125    var j = MONTHS.map(function (x) { return x.slice(0, 3); }).indexOf(m[1].toLowerCase().slice(0, 3));126    if (j >= 0) return { y: +m[3], m: j + 1, d: +m[2] };127  }128  m = line.match(/(\d{1,2})[\/.](\d{1,2})[\/.](\d{4})/);129  if (m) return { y: +m[3], m: +m[2], d: +m[1] };130  return null;131}132 133function toNum(d) { return d.y * 10000 + d.m * 100 + d.d; }134function monthsBetween(a, b) { return (b.y - a.y) * 12 + (b.m - a.m) - (b.d < a.d ? 1 : 0); }135 136// A labelled date lives on the label line or within the three lines that follow it.137function labelledDate(text, labelRe) {138  var lines = text.split('\n');139  for (var i = 0; i < lines.length; i++) {140    if (!labelRe.test(lines[i])) continue;141    for (var k = i; k <= i + 3 && k < lines.length; k++) {142      var d = findDate(lines[k]);143      if (d) return { date: d, line: k + 1 };144    }145    return { date: null, line: i + 1 };146  }147  return null;148}149 150function parseToday(opts) {151  var s = (opts && opts.today) || '';152  var d = findDate(String(s));153  if (d) return d;154  var n = new Date();155  return { y: n.getFullYear(), m: n.getMonth() + 1, d: n.getDate() };156}157 158function check(text, opts) {159  text = String(text == null ? '' : text);160  var today = parseToday(opts);161  var findings = [];162  var add = function (r, line, extra) {163    findings.push({ check: r.id, sev: r.sev, msg: extra ? r.msg + ' ' + extra : r.msg, line: line || 1 });164  };165 166  for (var i = 0; i < RULES.length; i++) {167    var r = RULES[i];168    var flags = r.flags || 'i';169    if (r.when && !new RegExp(r.when, flags).test(text)) continue;170 171    if (r.kind === 'require') {172      var re = new RegExp(r.pat, flags);173      if (!re.test(text)) {174        var anchor = r.when ? text.search(new RegExp(r.when, flags)) : -1;175        add(r, anchor >= 0 ? lineOf(text, anchor) : 1);176      }177 178    } else if (r.kind === 'forbid') {179      var fre = new RegExp(r.pat, flags.indexOf('g') < 0 ? flags + 'g' : flags);180      var hit;181      while ((hit = fre.exec(text)) !== null) {182        add(r, lineOf(text, hit.index), '(found: "' + hit[0].slice(0, 40) + '")');183        if (hit.index === fre.lastIndex) fre.lastIndex++;184        break;185      }186 187    } else if (r.kind === 'exclusive') {188      var seen = [], first = -1;189      for (var a = 0; a < r.alts.length; a++) {190        var pos = text.search(new RegExp(r.alts[a], flags));191        if (pos >= 0) { seen.push(r.alts[a]); if (first < 0 || pos < first) first = pos; }192      }193      if (seen.length > 1) add(r, lineOf(text, first), '(found: ' + seen.join(' + ') + ')');194 195    } else if (r.kind === 'date_present') {196      var got = labelledDate(text, new RegExp(r.label, flags));197      if (!got || !got.date) add(r, got ? got.line : 1);198 199    } else if (r.kind === 'date_future') {200      var gf = labelledDate(text, new RegExp(r.label, flags));201      if (gf && gf.date && toNum(gf.date) > toNum(today)) add(r, gf.line);202 203    } else if (r.kind === 'date_max_age') {204      var ga = labelledDate(text, new RegExp(r.label, flags));205      if (ga && ga.date) {206        var age = monthsBetween(ga.date, today);207        if (age > (r.months || 12)) add(r, ga.line, '(last review is ' + age + ' months old)');208      }209    }210  }211 212  findings.sort(function (x, y) { return x.line - y.line; });213  return { findings: findings };214}215 216var API = { engine: { check: check }, RULES: RULES, RULE_COUNT: RULES.length };217if (typeof module !== 'undefined' && module.exports) module.exports = API;218if (typeof window !== 'undefined') window.ASTMTENGINE = API;219</script>220<script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다.221'use strict';222function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;'); }223function summaryLine(res) {224  const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length;225  return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.';226}227function toText(res, label) {228  const f = (res && res.findings) || [];229  const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)];230  f.forEach(function (x) { lines.push('  ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + '  ' + (x.line ? 'L' + x.line + '  ' : '') + (x.check || x.id || '') + '  ' + (x.msg || x.message || '')); });231  return lines.join('\n');232}233function toHtml(res) {234  const f = (res && res.findings) || [];235  if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>';236  const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join('');237  return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>';238}239var ASTMTREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml };240if (typeof module !== 'undefined' && module.exports) module.exports = ASTMTREPORT;241else window.ASTMTREPORT = ASTMTREPORT;242</script>243<script>244(function(){245  var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today');246  today.value=new Date().toISOString().slice(0,10);247  function run(){ try { var res=window.ASTMTENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.ASTMTREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } }248  go.onclick=run; if (src.value.trim()) run();249})();250</script>251 252 253<section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://www.npmjs.com/package/@readystack/accessibility-statement-lint" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/accessibility-statement-lint" rel="noopener" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">npx @readystack/accessibility-statement-lint &lt;file&gt;254docker run --rm -v &quot;$PWD:/w&quot; getreadystack/accessibility-statement-lint /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://buy.polar.sh/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section>255<section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get one email when this rule changes</b><div style="opacity:.78;margin:.35rem 0 .8rem">We watch the regulation and vendor sources behind Accessibility Statement Lint (EU model) every day. When a rule changes, you get a single email with what changed and the updated check. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Notify me</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">You're on the list. One email when it changes.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"accessibility-statement-lint",lang:"en",source:"rule_alert"})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script></section>256 257<section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Checks the accessibility statement you already published against the EU model statement and its two dates</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A consultant charges $150-$250 an hour to review one statement; a full agency accessibility audit starts around $2,500.</p><a href="https://buy.polar.sh/polar_cl_DPpapwyFI9vWmYeB4f49Fp7BoXUo3CEvxfWmn16zHsc" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section>258<section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does Accessibility Statement Lint actually do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">It reads an accessibility statement you have already published and reports what the EU model statement requires and your file does not contain. Nineteen checks cover the commitment sentence, the legal basis, the compliance status wording, the three reason categories for non-accessible content, the disproportionate burden assessment, the date of preparation, the date of last review, the feedback channel and the enforcement procedure.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is this for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Public sector web teams in the EU, the digital agencies that publish on their behalf, and private-sector service providers now covered by the European Accessibility Act. If somebody on your team owns a page titled Accessibility statement, and a national monitoring body can sample that page without warning, this extension checks the exact file the body will read.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why can&#x27;t I just ask a chatbot or use a free accessibility checker?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A chat assistant writes you a brand new statement in seconds, but it cannot open the one already live on your domain, and it has no reliable sense of today&#x27;s date against your last review date. Free contrast and WCAG checkers test pages, not this document. The defects here are missing sections, stale dates and unfilled placeholders.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what needs a licence key?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free checks the statement file open in your editor and names every missing section, each finding on its own line in the Problems panel. That finishes the job for one statement. The licensed version sweeps every locale and sub-site statement in the workspace at once and writes one dated report carrying a per-file verdict.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What would this cost me otherwise?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">An accessibility consultant charges $150 to $250 an hour to read one statement against the model, and a full agency accessibility audit starts around $2,500. The licensed version is $29 once, one licence key per person or team seat, with a 7-day full refund. Checking a single file stays free and needs no key.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does Accessibility Statement Lint actually do?", "acceptedAnswer": {"@type": "Answer", "text": "It reads an accessibility statement you have already published and reports what the EU model statement requires and your file does not contain. Nineteen checks cover the commitment sentence, the legal basis, the compliance status wording, the three reason categories for non-accessible content, the disproportionate burden assessment, the date of preparation, the date of last review, the feedback channel and the enforcement procedure."}}, {"@type": "Question", "name": "Who is this for?", "acceptedAnswer": {"@type": "Answer", "text": "Public sector web teams in the EU, the digital agencies that publish on their behalf, and private-sector service providers now covered by the European Accessibility Act. If somebody on your team owns a page titled Accessibility statement, and a national monitoring body can sample that page without warning, this extension checks the exact file the body will read."}}, {"@type": "Question", "name": "Why can't I just ask a chatbot or use a free accessibility checker?", "acceptedAnswer": {"@type": "Answer", "text": "A chat assistant writes you a brand new statement in seconds, but it cannot open the one already live on your domain, and it has no reliable sense of today's date against your last review date. Free contrast and WCAG checkers test pages, not this document. The defects here are missing sections, stale dates and unfilled placeholders."}}, {"@type": "Question", "name": "What is free and what needs a licence key?", "acceptedAnswer": {"@type": "Answer", "text": "Free checks the statement file open in your editor and names every missing section, each finding on its own line in the Problems panel. That finishes the job for one statement. The licensed version sweeps every locale and sub-site statement in the workspace at once and writes one dated report carrying a per-file verdict."}}, {"@type": "Question", "name": "What would this cost me otherwise?", "acceptedAnswer": {"@type": "Answer", "text": "An accessibility consultant charges $150 to $250 an hour to read one statement against the model, and a full agency accessibility audit starts around $2,500. The licensed version is $29 once, one licence key per person or team seat, with a 7-day full refund. Checking a single file stays free and needs no key."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:0,slug:"accessibility-statement-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence, 7-day refund.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/en301549-lint"><span class="yj-rel-t">EN 301 549 Lint — European Accessibility Act rules, with the clause number, in</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/model-card-lint-gpai"><span class="yj-rel-t">Model Card Lint - EU GPAI (AI Act Art. 53)</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/amazon-fba-calculator-extension"><span class="yj-rel-t">FBA Profit &amp; Break-Even Calculator for Amazon Private-Label Sourcing — Chrome </span><span class="yj-rel-p">$60</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ai-model-license-lint"><span class="yj-rel-t">AI Model License Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ai-model-retirement-lint"><span class="yj-rel-t">AI Model Retirement Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/autohotkey-toml-devicetree-snippets"><span class="yj-rel-t">AutoHotkey v2, TOML and DeviceTree checks for VS Code</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section><!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div>259<script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||'')})}).catch(function(){});}catch(e){}})();</script>260</body>261</html>262