name: anysurfer-audit description: "Evaluate web components and Figma designs against the AnySurfer methodology, WCAG 2.2 AA, and Belgian accessibility law (EAA, Royal Decree 2019). Use this skill ONLY when AnySurfer is explicitly mentioned, when the user asks about the AnySurfer label, Belgian accessibility compliance, or EAA requirements. Do NOT trigger for generic accessibility questions, check a11y, or is this accessible — those are handled by the general accessibility-review skill. Trigger phrases: AnySurfer, AnySurfer label, Belgian accessibility, EAA compliance, does this meet AnySurfer, audit for AnySurfer."
AnySurfer Audit Skill
Evaluate digital components and designs against the AnySurfer methodology — the Belgian quality label for accessible websites, managed by Blindenzorg Licht en Liefde.
AnySurfer is based on WCAG 2.2, with level AA as the standard target and level A as the minimum threshold for the label. For Belgian public sector organisations, WCAG 2.1 AA is legally required (Royal Decree 05/09/2019 + Flemish Governance Decree 2018). From 28 June 2025, the European Accessibility Act (EAA) also applies to the private sector.
Input types
| Type | Approach |
|---|---|
| HTML/CSS/JS fragment | Static + semantic analysis |
| Figma URL or screenshot | Visual + structure analysis (via Penpot if connected) |
| Live URL | Analyse via web_fetch + static evaluation |
| Description/wireframe | Conceptual audit with recommendations |
If Penpot MCP is connected: use
tool_searchfor "penpot" to inspect designs directly for colour values, typography, and component structure. If Figma MCP is connected: usetool_searchfor "figma" to accessget_design_context,get_variable_defs, andget_metadatafor the same purpose. Figma MCP is available in the Claude connector registry but has not been formally tested against this skill — apply the same inspection approach as Penpot and report any gaps via GitHub.
AnySurfer evaluation framework
Conformance levels (per AnySurfer label)
| Level | Meaning | Label status |
|---|---|---|
| WCAG A | Basic accessibility | ✅ Minimum threshold for AnySurfer label |
| WCAG AA | Recommended level | ⭐ Target level for all sites |
| WCAG AAA | Advanced | 🎯 For niche/specialist audiences |
Audit checklist per WCAG principle
1. Perceivable
| Criterion | Level | Test point |
|---|---|---|
| 1.1.1 Non-text content | A | Alt text on all images; decorative images use alt="" |
| 1.2.1 Audio/video only | A | Transcript or description available |
| 1.2.3 Audio description or media alternative | A | Video with spoken content has audio description |
| 1.3.1 Info and relationships | A | Headings, lists, tables semantically marked up |
| 1.3.2 Meaningful sequence | A | Reading order logical without CSS |
| 1.3.3 Sensory characteristics | A | No instructions relying solely on colour/shape/position |
| 1.3.4 Orientation | AA | Not locked to portrait or landscape |
| 1.3.5 Identify input purpose | AA | Autocomplete attributes present on personal data fields |
| 1.4.1 Use of colour | A | Colour not the only distinguishing feature |
| 1.4.2 Audio control | A | Auto-playing audio can be stopped |
| 1.4.3 Contrast (minimum) | AA | ≥ 4.5:1 for normal text; ≥ 3:1 for large text (18pt / 14pt bold) |
| 1.4.4 Resize text | AA | Text scalable to 200% without loss of functionality |
| 1.4.5 Images of text | AA | No text as image unless essential |
| 1.4.10 Reflow | AA | Content usable at 320px width without horizontal scrolling |
| 1.4.11 Non-text contrast | AA | ≥ 3:1 for UI components and graphical elements |
| 1.4.12 Text spacing | AA | No content loss with custom letter/line spacing |
| 1.4.13 Content on hover or focus | AA | Tooltip/popover: dismissible, hoverable, persistent |
2. Operable
| Criterion | Level | Test point |
|---|---|---|
| 2.1.1 Keyboard | A | All functionality available without a mouse |
| 2.1.2 No keyboard trap | A | Focus can leave the component via keyboard |
| 2.1.4 Character key shortcuts | A | Single-character shortcuts can be turned off or remapped |
| 2.2.1 Timing adjustable | A | Time-limited sessions extendable or disableable |
| 2.3.1 Three flashes or below threshold | A | No content flashing more than 3 times per second |
| 2.4.1 Bypass blocks | A | Skip navigation link present |
| 2.4.2 Page titled | A | Descriptive <title> per page |
| 2.4.3 Focus order | A | Logical tab order (visual and DOM order) |
| 2.4.4 Link purpose (in context) | A | Link text understandable without surrounding context |
| 2.4.6 Headings and labels | AA | Headings descriptive; labels informative |
| 2.4.7 Focus visible | AA | Focus indicator visible on all interactive elements |
| 2.4.11 Focus not obscured (minimum) | AA | Focused component not fully hidden |
| 2.5.3 Label in name | A | Visible label is included in the accessible name |
| 2.5.5 Target size (enhanced) | AAA | Touch targets ≥ 44×44 CSS pixels (AnySurfer recommends this for AA too) |
| 2.5.8 Target size (minimum) | AA | Touch targets ≥ 24×24 CSS pixels |
3. Understandable
| Criterion | Level | Test point |
|---|---|---|
| 3.1.1 Language of page | A | lang attribute present on <html> |
| 3.1.2 Language of parts | AA | Language changes marked with lang attribute |
| 3.2.1 On focus | A | No unexpected context change on focus |
| 3.2.2 On input | A | No unexpected context change on input (unless announced) |
| 3.2.3 Consistent navigation | AA | Navigation consistent across pages |
| 3.2.4 Consistent identification | AA | Components with the same function consistently named |
| 3.3.1 Error identification | A | Errors described in text, not by colour alone |
| 3.3.2 Labels or instructions | A | Every input field has a visible label |
| 3.3.3 Error suggestion | AA | Correction suggested where known |
| 3.3.4 Error prevention | AA | Important actions confirmable/reversible |
4. Robust
| Criterion | Level | Test point |
|---|---|---|
| 4.1.2 Name, role, value | A | ARIA roles, names and states correct on all UI components |
| 4.1.3 Status messages | AA | Status messages programmatically available (without receiving focus) |
AnySurfer-specific considerations
Beyond WCAG, AnySurfer also checks:
- PDF accessibility: Tagged PDFs, readable form fields, alternative text in documents
- Multilingualism: Correct
langattributes for NL/FR/EN language switches (relevant for Belgian government) - CMS editor management: Editors can publish accessible content (alt text, headings)
- Mobile accessibility: Responsive design, adequate touch target sizes
- Video subtitling: Informational programmes fully subtitled
Evaluation approach per input type
For HTML/CSS/JS components
Check in order:
- Semantics: Correct HTML elements (
<button>vs<div>,<nav>, heading structure) - ARIA: Roles, names, states complete and correct
- Keyboard: Focus, tab order, Enter/Space/Escape behaviour
- Contrast: Calculate ratios for text and UI elements
- Responsive: Reflow at 320px, touch target sizes
For Figma/Penpot designs
Check in order:
- Colour contrast: Extract hex values, calculate ratios
- For solid colours: calculate ratio directly against the background
- For gradient text (2 stops): check both endpoint stops — the lightest stop is the worst case
- For gradient text (3+ stops): check every stop individually — a mid-stop may be lighter than both endpoints and become the actual worst case
- For gradient backgrounds (element on top): sample the background colour at the exact position behind the element, then calculate against that single value (not the gradient endpoints)
- For radial gradients: worst-case position depends on where the element sits relative to the gradient centre — sample accordingly
- Typography: Font size, weight → impact on contrast threshold
- Component names/annotations: Are ARIA labels visible in the design?
- Focus states: Are hover and focus states designed?
- Touch target sizes: Are buttons and links at least 24×24px (WCAG) or 44×44px (AnySurfer recommendation)?
- Information density: Is colour used as the only distinguishing feature?
If Penpot MCP is connected: use
Penpot:high_level_overviewthenPenpot:penpot_api_infoto retrieve component data for direct inspection.
Output format
## AnySurfer Audit: [Component/page name]
**Standard:** WCAG 2.2 AA (AnySurfer methodology) | **Date:** [date]
**Input type:** [HTML / Figma / URL / Description]
### Summary
**Findings:** [X] | 🔴 Critical: [X] | 🟠 Important: [X] | 🟡 Minor: [X] | ✅ Passed: [X]
**AnySurfer label status (estimate):**
- Level A: [Passed / Failed]
- Level AA: [Passed / Failed / Partial]
---
### 🔴 Critical findings (Level A — blocks label)
| # | Finding | WCAG criterion | Element | Recommendation |
|---|---------|----------------|---------|----------------|
| 1 | [Description] | [1.4.3 Contrast] | [selector/component] | [Concrete fix] |
### 🟠 Important findings (Level AA — required for full label)
| # | Finding | WCAG criterion | Element | Recommendation |
|---|---------|----------------|---------|----------------|
### 🟡 Minor findings / improvements
| # | Finding | WCAG criterion | Element | Recommendation |
|---|---------|----------------|---------|----------------|
### ✅ Correctly implemented
- [Criterion]: [What is correct]
---
### Colour contrast check
| Element | Foreground | Background | Ratio | Required | Result |
|---------|-----------|------------|-------|----------|--------|
| [Body text] | #333 | #fff | 12.6:1 | 4.5:1 | ✅ |
### Keyboard navigation
| Element | Tab order | Enter/Space | Escape | Arrow keys |
|---------|-----------|-------------|--------|------------|
### Screen reader — predicted output
> ⚠️ **Disclaimer:** Claude cannot run a screen reader. The following is a structural prediction based on static analysis of HTML, ARIA attributes, and role assignments. It reflects what a screen reader such as NVDA or VoiceOver would *likely* announce, but cannot substitute for real testing with assistive technology. AnySurfer certification always includes human testing with an actual screen reader.
| Element | Predicted announcement | Issue |
|---------|----------------------|-------|
| [e.g. icon button] | [e.g. "button" — no name] | [Missing aria-label or visible label] |
| [e.g. error message] | [e.g. silence] | [Not in aria-live region — never read aloud] |
| [e.g. decorative image] | [e.g. filename.png] | [Missing alt="" — filename announced instead] |
### Priority fixes
1. 🔴 **[Critical fix]** — Blocks AnySurfer level A
2. 🟠 **[AA fix]** — Required for full label
3. 🟡 **[Improvement]** — Best practice
### Next steps towards the AnySurfer label
- [ ] Resolve critical findings (level A)
- [ ] Resolve AA findings
- [ ] Repeat audit (AnySurfer requires a minimum of 2 test rounds)
- [ ] Publish accessibility statement
Common JS-driven accessibility fix patterns
When a finding involves a JavaScript-driven component, point the user to the relevant pattern below. Do not generate implementation code in the audit report — the fix must be applied in context by someone who understands the specific architecture.
| Finding | Pattern | Key attributes / approach |
|---|---|---|
| Hidden content still read by screen reader | Add aria-hidden="true" to non-visible containers; remove it when they become visible |
el.setAttribute('aria-hidden', 'true') / el.removeAttribute('aria-hidden') |
| Active tab / step not communicated | Toggle aria-current="true" on the active element in the same JS function that toggles visual state |
el.setAttribute('aria-current', 'true') |
| Button label doesn't reflect current state | Update aria-label dynamically when button text changes, or when context changes |
btn.setAttribute('aria-label', 'Back to Context') |
| Dropdown / menu: expanded state not communicated | Toggle aria-expanded="true/false" on the trigger when the panel opens/closes |
Pair with aria-controls="panel-id" on trigger |
| Modal / dialog: focus not managed | Move focus into the dialog on open; return focus to trigger on close; trap Tab/Shift+Tab inside | dialog.querySelector('[autofocus]').focus() |
| Modal: background content still readable | Add aria-hidden="true" to <main> or page wrapper when modal is open; remove on close |
Never put aria-hidden on the modal itself |
| Live region not announcing updates | Wrap dynamic content in aria-live="polite" (non-critical) or aria-live="assertive" (urgent) |
Add aria-atomic="true" if the whole region should be re-read on any change |
| GSAP / CSS animations ignore reduced motion | Wrap all animations in a prefers-reduced-motion media query check |
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) |
| Progress bar has no label | Add aria-label or aria-labelledby to role="progressbar" |
aria-label="Step progress" |
| Carousel / slider: current item not communicated | Set aria-roledescription="slide" on items; use aria-label="1 of 5" pattern |
Update on transition |
| Infinite scroll / dynamic content load | Announce new content via aria-live region; ensure new items are keyboard reachable |
Avoid focus stealing on load |
| Custom select / listbox | Use role="listbox" + role="option" + aria-selected; manage focus with arrow keys |
Follow ARIA Authoring Practices Guide listbox pattern |
| Icon-only button | Add aria-label describing the action, not the icon |
<button aria-label="Close dialog"> |
| Tooltip on hover/focus | Ensure tooltip is dismissible (Escape), hoverable, and persistent (1.4.13) | Use role="tooltip" + aria-describedby on the trigger |
For complex patterns (modals, carousels, custom widgets), refer to the ARIA Authoring Practices Guide for the canonical implementation pattern.
Reference files
Read when relevant:
references/wcag22-quick-ref.md— Full WCAG 2.2 success criteria with explanationsreferences/anysurfer-context.md— Belgian legal context, EAA, label process
Tips
- Start with contrast and keyboard — These are the most common and impactful issues.
- Level A first — Without level A, the AnySurfer label cannot be awarded.
- Design audit ≠ dev audit — A Figma audit checks intent; an HTML audit checks implementation. Both are needed.
- AnySurfer always does at least 2 test rounds — Initial audit + retest after fixes.
- EAA deadline: New products/services in the private sector must comply from 28 June 2025.