A11y Gate: The Accessibility Gate for Statamic Icon

A11y Gate: The Accessibility Gate for Statamic

0.9.0

September 10th, 2026

Added

A panel block may name a refusalKey. Statamic puts a 422's errors onto the publish container exactly as they were sent, and hard-codes the toast to "The given data was invalid", so an addon that refuses a save has nowhere of its own to say why. Keying the refusal to a blueprint field puts it under that field, where it reads as a fault in the field: A11y Docs was keying "this entry links to a document nobody can read" to title. A block that names a key has whatever is under that key drawn in the block instead, in place of its standing lines and above its link. The key has to be shaped like a handle.

PanelExtensions::supports() answers whether this version draws a given capability, today only refusalKey. A provider ships on its own release cycle, and naming a key at a gate too old to read one sends the refusal somewhere nothing draws without failing: the save is still refused and the author is never told why.

0.8.1

September 10th, 2026

Fixed, where the addon was saying something untrue

The all-clear badge now says what it was an all-clear about. It reads "Nothing to fix in the page itself". This gate checks the rendered HTML and cannot open a linked document, so a PanelExtensions block underneath it can report a PDF a screen reader cannot open on the same screen. A flat "Nothing to fix" above that was two verdicts with nothing to tell them apart. The wording does not depend on what else is installed: a badge that means one thing alone and another in company would be harder to trust, not easier.

0.8.0

September 7th, 2026

Added

A link under each finding to the W3C's page on the criterion it cites. "WCAG 1.1.1 Non-text Content" under an image finding opens the Understanding page for it, in a new tab that is announced. Underlined and coloured for both themes, because the control panel resets anchors to look like text. A house rule such as "Heading structure" cites no criterion and has no link. The check endpoint sends the reference as reference on each finding, null for a house rule.

A block in the panel may carry a mark. PanelExtensions blocks take an optional mark of a url and an alt, drawn above the block's heading at about the height of a line of text, so a companion addon's block can be recognised as the site owner's own. The gate holds no branding of its own and gains no setting: it draws what a provider hands it. A mark with no words is left out, and so is an address that is not a path, an http or https URL, or a data:image/ value. A block reporting a problem wears no mark.

What to do about it: republish the addon's assets if your deploy does not (php artisan vendor:publish --tag=laravel-assets --force).

0.7.0

September 2nd, 2026

One addition and nothing removed.

A seam in the panel for another addon. PanelExtensions::register() takes a callable that, given the entry, returns a block to draw beneath the gate's own result on the entry screen: a heading, plain lines, an optional link. Nothing about the checks or the refusal changes: a provider cannot add a finding, alter one, or affect a save, and one that throws is drawn as a warning rather than dropped. Accessibility Report uses it to show a page's open issues from the last scan.

What to do about it: nothing. Without a provider registered the panel is what it was.

0.6.0

August 19th, 2026

Removed, and it can break a site

ReadingLevel::grade() is gone, along with the three private helpers behind it.

It is very unlikely you were calling it. It was never called by the addon itself, in any commit, and it was named in no README line, no config comment and no decision entry, so the only way to find it was to read src/. There is no Antlers tag or modifier for it, so no template could have reached it.

If you were calling it, from a listener or a service that stamps data-a11y-reading-grade on your plain-language summaries, that call is now a fatal error. Compute the grade yourself instead. The formula the threshold is calibrated against is Flesch-Kincaid:

0.39 x (words per sentence) + 11.8 x (syllables per word) - 15.59

ReadingLevel::PLAIN_MAX_GRADE stays, and is still the number the check compares your stamped grade against.

Why it was removed rather than documented: its syllable count stripped every character outside a-z, so a word in Japanese, Arabic or Russian counted as one syllable and the grade collapsed into a function of sentence length alone. Real passages in those scripts scored 0.0 and 0.1 against a threshold of 9, which is a confident-looking pass for text the formula has no opinion about. Publishing that as a supported API was not something this addon could do honestly, and leaving it in place unused and undeclared was the ambiguity that got it noticed.

There is deliberately no deprecation shim. A method that still returns 0.1 for Arabic is worse kept than removed.

Fixed, where the addon was saying something untrue

  • A page whose only media was a figure was told to confirm that its video had captions. It has no video. A page that did carry the markup for captions, transcripts, figure text and footnotes was told that captions "are only checked on sites that mark them up, and this one does not", in the same report as a finding only that markup could have produced.
  • The Accessibility Gate page under Tools said there were three exceptions that do not stop a publish. There are four: link text that is vague rather than plainly wrong was missing. The same page said the entry "is not saved" without mentioning that report mode is a setting on the screen it sends you to, gave 24 pixels as the touch target minimum without saying a config file raises it to 44, and said "embedded videos" where the rule checks every frame, maps and forms included.
  • In report mode the log said "This entry was not saved" about an entry that was saved.
  • The site-wide scan counted a page once per finding rather than once. A page with three identical "Read more" links reported as three pages, stopped naming the page it was on, and on a small site could claim "every page", which is the line that sends somebody to rewrite a template.

Changed, with no difference to what is reported

  • Severity now lives with the rule rather than being passed at each of the eighteen places a rule is raised. A rule can no longer be raised at two different severities, and a typo can no longer turn a refusal into a warning.
  • The opt-in setting is read once, by the checker. Every check now always answers how much of the page it could see, so a check can no longer drop out of the count and make "4 of 5 checks ran" read as "4 of 4".
  • AccessibilityStandard is a backed enum. It used to be three fields anyone could set, so a label claiming AAA could sit over a minimum of 7 pixels.
  • The corpus refuses to run against a fixture it cannot read, and pins its cases by name rather than by counting them.

Verified across all 28 corpus fixtures, before and after, including every message, call to action and pointer: no finding changed.

0.5.4

November 29th, -0001

  • N/A Changelog not available.

0.5.3

November 29th, -0001

  • N/A Changelog not available.