Guardrail Blocks
Guardrail Blocks
Description
Most accessibility failures on WordPress sites are authoring failures: a brand color that doesn’t meet WCAG contrast, a heading hierarchy scrambled by reordering, an accordion built from divs with no keyboard support. They look fine in the editor and fail the audit later.
Guardrail Blocks takes a different approach: instead of offering accessible options, its blocks make the failure impossible to author — and re-verify everything on every page view.
The guarantees
- WCAG-safe color contrast — Button backgrounds come only from your theme’s palette, and the most readable text color is chosen automatically (the live ratio is shown in the sidebar, e.g. “Contrast 8.36:1 — AA ✓”). The pairing is re-validated server-side on every page view against your theme’s current palette, so switching themes or changing brand colors can never leave a failing button behind.
- Unbreakable heading hierarchy — There is no heading level control anywhere. An Accessible Heading derives its level (H2–H6) from how Accessible Sections are nested, and re-derives it when you reorder, nest, or un-nest — the document outline stays valid by construction. Card titles and accordion headers participate too, always one level below their section’s heading.
- Correct interactive semantics — The Accordion ships the full WAI-ARIA disclosure pattern: real buttons inside correctly-leveled headings,
aria-expanded/aria-controlswiring, Enter/Space toggling, arrow-key navigation between headers, and content that stays reachable without JavaScript. - Performance-correct media — The Media Figure renders through core’s responsive-image pipeline with explicit dimensions (no layout shift),
srcset/sizes, a hero toggle forfetchpriority="high"(better LCP) vs. lazy loading, and alt text enforcement with editor warnings.
The blocks
Accessible Section, Accessible Heading, Accessible Button, Card + Card Grid, Accessible Accordion, Notice (info/success/warning/error with correct ARIA roles), Media Figure, and a Table of Contents that is generated from the page’s real outline on every view — it can never go stale.
Safety nets
- The Outline Checker panel (in the page sidebar) watches the whole document — including core Heading blocks — and flags skipped levels and extra H1s with one-click block selection.
- Everything inherits your theme’s colors, spacing, and typography via
theme.json. Nothing fights your design. - The plugin makes zero external requests and collects no data.
Source code & development
The compiled block scripts in build/ are generated with @wordpress/scripts (webpack). The complete, human-readable source code is included with this plugin in the src/ directory (TypeScript and SCSS, one folder per block). To rebuild build/ from it: npm install && npm run build (Node 22; package.json and tsconfig.json are included).
Development happens publicly at https://github.com/breonwilliams/guardrail-blocks, which also carries the full test suite (Jest, PHPUnit, Playwright) and CI.
Faq
No. It’s a focused set that mixes freely with core blocks — use core paragraphs, images, and columns as usual. The Outline Checker even watches headings you author with the core Heading block.
It inherits your theme’s own button styling (the same wp-element-button mechanism core’s Button uses), so it always looks like a button. The contrast guarantee applies the moment you pick a palette background; the theme-default state’s contrast is the theme’s responsibility, exactly as with core buttons.
Yes. Palettes in the var(--name, #hex) format used by many popular themes are fully supported. A color whose value genuinely can’t be resolved (for example color-mix(...)) is not offered for buttons rather than being silently unchecked, and the sidebar explains why.
That’s the point: hand-picked levels are how outlines break. The level always derives from section nesting, so reordering can never skip a level or create a second H1. If you need a specific level, nest (or un-nest) the section — the outline follows the structure.
Static content (sections, cards, notices’ inner content) remains as clean HTML. Dynamic blocks (headings, buttons, accordions, table of contents) stop rendering their markup but your content is preserved and reappears on reactivation — nothing is lost.
No. Zero external HTTP requests, no tracking, no accounts.
Reviews
Changelog
0.1.1
- Heading levels are now also derived from the block tree’s actual nesting on every render, so a stored level can never produce a wrong heading — the outline guarantee is enforced server-side end to end.
- New theme-friendly design controls via core block supports: border on Card and Accordion; border radius on Button and Media Figure (rounds the image); padding on Accordion; font size on Accordion, Notice, and Table of Contents; margin on Accessible Heading.
- Fixed: the Button’s border radius now previews live in the editor with themes that style
wp-element-button(Blocksy and similar).
0.1.0
- Initial release.
- Blocks: Accessible Section, Accessible Heading, Accessible Button, Card + Card Grid, Accessible Accordion, Notice, Media Figure, Table of Contents.
- Contrast engine (editor + server) with support for hex, rgb(), and var()-fallback theme palettes.
- Heading levels derived from section nesting with self-correction on reorder; Outline Checker panel.
- Accordion built on the WordPress Interactivity API with the WAI-ARIA disclosure pattern.
- Five patterns including the Starter Brochure Page.