Table des matières

1 - Accessibility Coding Guidelines

Accessibility Coding Guidelines

This guide provides actionable DOs and DON’Ts for AI coding agents to ensure web applications are accessible to all users, including those using assistive technologies.

Keep these principles in mind throughout:

  • Accessibility is the minimum, not the ceiling. Conformance to standards is the floor; aim for genuine usability.
  • Patterns are use-case specific. No checklist replaces real testing — including testing with disabled users — to confirm a given implementation is actually accessible in context.

1. Content Navigability and Structure

Actionable Guidelines

DOs

  • Place all content within landmarks: Wrap the page in <header>, <nav>, <main>, <aside>, and <footer> so assistive-tech users can jump between regions.
  • Structure main content with headings: Use <h1><h6> sequentially (no jumping <h1><h4>) so screen-reader users get a navigable outline.
  • Use lists for repeated, contiguous content: <ul>/<ol> give assistive tech a count up front and let users skip the entire group.
  • Provide skip links prior to repeated content like site headers with navigation or long/infinite lists, so that keyboard users can easily bypass them. Make sure the target is focusable (e.g. <main id="content" tabindex="-1">).
  • Semantic Tables: Use <caption> and <th scope="col"> (or <th scope="row">) for data tables.

DON’Ts

  • Don’t use fake headings: Never style <div> or <span> to look like headings without standard <h1><h6> tags.
  • Don’t place headings inside <summary>, and avoid relying on headings inside <details> content: Headings inside <summary> may be hidden from screen-reader heading lists and heading-navigation shortcuts entirely; headings inside <details> content are only reachable via heading navigation when the disclosure is open.
    • Caveat: If a heading must act as a disclosure trigger, use a more robust alternative to <details>/<summary> instead, e.g. an accordion or a disclosure implemented with ARIA where the heading wraps the button.
  • Don’t use tables for layout: Use CSS Grid/Flexbox for visual layouts.
  • Don’t overuse landmarks: Too many landmarks dilute their value. In particular, avoid labeling a <section> (which turns it into a region landmark) — region should be a last resort when no other landmark fits.

Code Examples

html
<!-- Good: Semantic landmarks, heading hierarchy, skip link -->
<header>
  <a href="#content" class="skip-link visually-hidden">Skip to content</a>
  <nav aria-label="Primary">
    <ul>
      <li><a href="/">Home</a></li>
    </ul>
  </nav>
</header>
<main id="content" tabindex="-1">
  <h1>Platform Dashboard</h1>
  <section>
    <h2>User Statistics</h2>
    <table>
      <caption>Monthly active users</caption>
      <tr>
        <th scope="col">Month</th>
        <th scope="col">Users</th>
      </tr>
      <tr>
        <td>January</td>
        <td>12,000</td>
      </tr>
    </table>
  </section>
</main>

2. Semantic HTML and ARIA

Actionable Guidelines

DOs

  • Prefer HTML elements and attributes to ARIA: A native element comes with the right role and behavior. <button> already implies role="button"; required already implies aria-required.
  • Match ARIA implementations to actual behavior: If you set role="tab", the element must behave like a tab — including keyboard interactions. Many ARIA patterns can’t be implemented in CSS alone and need JavaScript.
  • Be deliberate about disabled vs aria-disabled: disabled removes the element from the focus order entirely (and tabindex="0" won’t bring it back), which is often wrong for toolbar buttons or links. aria-disabled="true" keeps the element focusable so users can land on it and learn it’s disabled.

DON’Ts

  • Don’t use ARIA when native HTML exists: Avoid <div role="button"> or <a role="button"> if <button> works.
  • Don’t add redundant ARIA roles or properties: Avoid <ul role="list">, <nav role="navigation">, or <input required aria-required="true">.
    • Caveat: Safari removes list semantics from <ul>/<ol> outside <nav> when list-style: none or display: flex/grid is applied. In that case role="list" is required to restore them.
  • Don’t assume custom elements have no ARIA: Custom elements can attach ARIA via ElementInternals, which some automated test tools can’t see — so the absence of role/aria-* attributes in markup doesn’t prove the element has no semantics. Verify with the browser’s accessibility-tree inspector.

3. Accessible Names and Descriptions

Every interactive element and some landmarks need an accessible name, and many benefit from an accessible description. Names are short and identify the element; descriptions add context.

Actionable Guidelines

DOs

  • Prefer native naming mechanisms: <label> for form controls, <caption> for <table>, <legend> for <fieldset>, <figcaption> for <figure>.
  • Explicitly associate <label> with its control via for/id, even when nesting the input inside the label — explicit association improves assistive-tech support.
  • Prefer aria-labelledby over aria-label when a visible label exists: avoids duplication, improves maintainability, and translates better.
  • Prefer to reuse the same accessible name for hyperlinks that share an href.
  • Use visually hidden text to disambiguate controls that look identical visually but do different things (e.g. multiple “Edit” buttons in a list).

DON’Ts

  • Don’t put aria-label/aria-labelledby on elements that shouldn’t be named — e.g. plain <div>, <span>, or custom elements without a role. Custom elements may have an implicit role set via ElementInternals, so the absence of a role attribute isn’t conclusive.
  • Don’t reuse an accessible name across controls with different effects in the same view (close buttons for two different open dialogs are fine because only one is reachable at a time; multiple “Edit” buttons for different content is not).
  • Don’t reuse an accessible name across hyperlinks pointing to different hrefs.
  • Don’t pack descriptions, error messages, or instructions into the label.
  • Don’t repeat state already exposed via ARIA (aria-expanded, aria-checked, aria-selected, aria-pressed) inside the accessible name — it creates redundancy and ambiguity.
  • Don’t include the role name in the label: <nav aria-label="Primary navigation"> reads as “Primary navigation navigation.”
  • Don’t use title or placeholder as a naming mechanism.
  • Don’t include interactive elements in an aria-describedby target unless their text content reads sensibly as a description on its own (e.g. if a link’s text is the same as how it’s labelled elsewhere, it can be included within a description).

Code Example: Visually Hidden Utility

A .visually-hidden utility lets you provide text for screen readers without rendering it visually. It’s commonly used for skip links, additional context on icon-only buttons, and supplementary labels.

css
/* Hides content visually but keeps it in the accessibility tree.
   :focus-within / :active opt elements out — useful for skip links and
   any focusable content wrapped in this class. */
.visually-hidden:where(:not(:focus-within, :active)) {
  position: absolute !important;
  clip-path: inset(50%) !important;
  overflow: hidden !important;
  width: 1px !important;
  height: 1px !important;
  margin: -1px !important;
  padding: 0 !important;
  border: 0 !important;
  white-space: nowrap !important;
}

When the hidden content is focusable (skip links, focus-receiving wrappers), the :focus-within/:active exception lets it become visible. Style the visible state per situation, e.g. a skip link to the main content typically wants fixed positioning at the top-left of the viewport so the rest of the page doesn’t shift.

4. Document Metadata and Language

Actionable Guidelines

DOs

  • Declare Visual Language: Always set <html lang="en"> (or appropriate code).
  • Unique Page Titles: Front-load unique context in <title> (e.g., Page Topic | Site Name).
  • Inline Language Switches: Use lang="..." for block quotes or text in different languages.
  • IFrame Titles: Always provide a descriptive title="..." for <iframe> elements.
  • Update document title on Page Transitions in SPAs: Shift focus to updated titles.

DON’Ts

  • Don’t Disable iframe Scrolling: Avoid scrolling="no" (deprecated) or overflow: hidden on iframes. Users who zoom in or enlarge text need to scroll to reach content that overflows.

Code Examples

html
<!-- Good: Distinct title and language declaration -->
<html lang="en">
<head>
  <title>Analytics Reports | Guidance Platform</title>
</head>
<body>
  <p>The motto is <span lang="la">"Carpe diem"</span>.</p>
  <iframe title="Interactive Sales Chart" src="/chart"></iframe>
</body>
</html>

5. Keyboard and Focus Management

Actionable Guidelines

DOs

  • Logical Tab Order: Ensure tab order matches visual layouts (top-to-bottom).
  • Visible Focus Indicators: Always style :focus-visible states explicitly. If disabling defaults, provide overrides with sufficient contrast.
  • Custom Trigger Keyboards: Attach Enter/Space handlers for custom simulated interactive elements. When implementing a custom keyboard handler for button-like elements, Enter should be a keydown handler and Space should be a keyup handler (matching native <button> behavior where Enter repeats and Space triggers on release).
  • Use tabindex deliberately: Anything focusable — by keyboard or programmatically — should have an implicit or explicit ARIA role, so don’t make every element focusable. When focus is needed, choose tabindex="0" to add the element to the tab order or tabindex="-1" to make it programmatically focusable only (e.g., a skip-link target).
  • Manage Toggle States: Utilize aria-expanded and aria-pressed to communicate toggle states for custom controls.

DON’Ts

  • Don’t disable outlines without replacements: Avoid outline: none without styling alternatives.
  • Don’t use Positive Tabindex values: Never use tabindex="1" or greater.
  • Don’t hide interactive elements from screen readers: Avoid aria-hidden="true" or role="presentation" on elements that can receive focus.

Code Examples

css
/* Good: High contrast focus border */
:where(a:any-link, button):focus-visible {
  outline: 3px solid #ff0055;
  outline-offset: 3px;
}
html
<!-- Good: Skip to main content -->
<a href="#content" class="skip-link">Skip to main content</a>
<main id="content" tabindex="-1">...</main>
javascript
// Good: Keyboard handlers for complex custom widgets (e.g., Tree items, tabs).
// NOTE: This pattern applies ONLY to non-standard UI where no native HTML tag exists.
// Always prioritize native <button> or <input> elements for standard interactions.
// Elements MUST have the appropriate ARIA role (e.g., role="treeitem" or role="tab").
customWidget.addEventListener('keydown', (e) => {
  if (e.key === 'Enter') {
    toggleWidgetState();
  }
  if (e.key === ' ') {
    e.preventDefault(); // Prevent page scrolling on Spacebar keydown
  }
});

customWidget.addEventListener('keyup', (e) => {
  if (e.key === ' ') {
    toggleWidgetState();
  }
});

function toggleWidgetState() {
  // E.g., Manage toggle/expanded states for custom controls
  const isExpanded = customWidget.getAttribute('aria-expanded') === 'true';
  customWidget.setAttribute('aria-expanded', !isExpanded);
}

6. Alternate Text and Media

Actionable Guidelines

DOs

  • Informative Visual Descriptions: Describe the purpose of the image (e.g., “Search”, not “Magnifying glass”).
  • Empty Alt properties for decorative visuals: Use alt="" to remove decorative images from the accessibility tree so they aren’t announced.
  • Synchronous Captions for videos: Supply WebVTT captions for video tracks.
  • Transcripts for audio: Provide text transcripts for purely audio podcasts.
  • Informative View Descriptions for inline SVGs: Apply role="img" and a nested <title> tag for informative visuals.
  • Decorative SVGs removal: Apply aria-hidden="true" to remove decorative SVGs from reading flows.
  • Long descriptions for complex images: Use <figure>/<figcaption> or aria-describedby for charts and infographics.
  • Provide data tables as alternatives: Consider providing semantic data tables as accessible alternatives for charts and other complex data visualizations.

DON’Ts

  • Don’t use clichéd prefixes: Avoid “Image of…” or “Picture of…”.
  • Don’t use underscores in filenames: Use dashes if the filename might be announced as fallback.

Code Examples

html
<!-- Decorative -->
<img src="divider.png" alt="">

<!-- Inline Decorative SVG (remove from tab flow) -->
<svg aria-hidden="true" viewBox="0 0 24 24">
  <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"/>
</svg>

<!-- Informative (Functional) -->
<a href="/search">
  <img src="glass.png" alt="Search the platform">
</a>

<!-- Video with Captions tracks -->
<video controls>
  <source src="intro.mp4" type="video/mp4">
  <track src="caps.vtt" kind="captions" srclang="en" label="English">
</video>

<!-- Complex graph with figcaption -->
<figure>
  <img src="chart.png" alt="Sales growth graph 2024.">
  <figcaption>Sales grew 20% in Q3 due to new platform launch.</figcaption>
</figure>

<!-- Audio with expandable transcript details -->
<audio controls src="podcast.mp3" aria-details="podcast-transcript"></audio>
<details id="podcast-transcript">
  <summary>View Transcript</summary>
  <div class="transcript-content">
    Welcome to the show...
  </div>
</details>

Content Visibility Decision Matrix

IntentVisualScreen ReaderFocusableStructural Pattern
Visible to allYesYesYesStandard rendering
Screen Reader onlyNoYesYes (if interactive)Visually hidden utility (e.g. .visually-hidden)
Visual onlyYesNoNoaria-hidden="true" / role="presentation"
Hidden for allNoNoNohidden attribute / display: none

Heuristic Rule: If an element can receive keyboard focus, it must not be hidden via aria-hidden="true".

7. Forms and Input Controls

Actionable Guidelines

DOs

  • Connect Labels Programmatically: Use <label for="id"> linked to <input id="id">.
  • Use Autocomplete: Set valid standard autocomplete options (e.g., "email" or "given-name") for user profiles.
  • Link hints to inputs via aria-describedby: Associate help text with inputs, and place the hint above the input so autocomplete popovers don’t cover it during editing.
  • Announce dynamic errors via live regions: Use aria-live or shift focus to error lists.
  • Provide form validation constraints: Use required (or aria-required="true" only when required isn’t applicable) to signal mandatory inputs.

DON’Ts

  • Don’t use placeholders as labels: Placeholders are not persistent labels.
  • Don’t trigger context shifts on focus changes: Avoid auto-submitting forms or jumping pages on focus change events alone.

Code Examples

html
<!-- Good: Semantic forms with hints for passwords -->
<form>
  <label for="pwd">Password:</label>
  <span id="pwd-hint">Must contain at least 8 characters.</span>
  <input id="pwd" type="password" aria-describedby="pwd-hint" autocomplete="current-password" required>
</form>

8. Live Regions

Live regions let assistive tech announce content updates that aren’t tied to navigation or focus changes. They’re easy to misuse — too many regions, or noisy ones, quickly become spam for screen-reader users.

Live Region Urgency Table

UrgencyVisual Analoguearia-live ValueBehavioral ImpactExample
CriticalModal / Alertassertive (or role="alert")Interrupts immediately, clears speech queueSession timeout, API failure
StandardToast / BannerpoliteAnnounces at next graceful breakSearch results, “Saved” status
PassiveSilent textoffOnly if user navigates to itLive character count

Heuristic Rule: Use assertive only for critical, time-sensitive updates that require immediate attention or prevent safe continuation (e.g., data loss, session timeouts, or network drops).

Actionable Guidelines

DOs

  • Centralize live regions for non-visible announcements: A single polite region and a single assertive region per page (with whatever aria-atomic configuration you need) keeps announcements consistent and easier to maintain. Many frameworks ship their own announcer abstraction — use it.
  • Debounce frequently-changing regions: If a region can update many times per second (e.g. a combobox’s result count as the user types), debounce so users aren’t spammed.
  • Delay slightly when other announcements may collide: When the user is typing or focus is being managed, a small delay before announcing keeps live-region updates from overlapping other speech.

DON’Ts

  • Don’t use live regions for interstitial states like “Loading…” or “Updating…” unless they’re meaningfully informative — they usually just create noise.
  • Don’t add live-region updates to inert DOM: When dialogs open or sections become inert, queued or debounced messages can end up unannounced — or announced from DOM the user can’t reach. Coordinate live-region updates with dialog/inert state changes.

Code Example

html
<!-- Session Timeout Warning with controls -->
<div role="alert" class="timeout-warning">
  Your session will expire in 2 minutes. 
  <button type="button" onclick="extendSession()">Extend Session</button>
</div>

9. Color, Contrast, and Typography

Actionable Guidelines

DOs

  • Minimum contrast standards: Maintain 4.5:1 for normal text and 3:1 for large text or icons.
  • Ensure non-text contrast standards: Maintain a minimum contrast ratio of 3:1 for user interface component boundaries and states.
    • This includes visual elements (borders, backgrounds, box-shadows, underlines) that form the boundary or indicate the presence of a UI component (e.g., input field borders).
    • This also includes visual elements indicating active states within a component (e.g., checkbox checkmarks or switch thumbs).
    • Caveat: Meeting 3:1 non-text contrast can challenge minimalistic designs. Soft gradients or subtle inset/outset shadows can soften visual boundaries while satisfying accessibility requirements.
  • Use multiple state indicators: Do not denote success/errors ONLY with color. Use icons or text.
  • Relative font size units: Use rem or em for font sizes instead of px.
  • Consistent or Start alignment: Avoid justify alignment as it can be more difficult to read.
  • Avoid long lines of text: Cap paragraph blocks to a maximum of 80 characters width.
  • Support user zoom preferences: Allow users to resize text up to 200% without loss of content or functionality.
  • Support light and dark color schemes: Honor @media (prefers-color-scheme: dark) and pair it with the color-scheme CSS property so form controls, scrollbars, and other UA-rendered surfaces match.
  • Use prefers-contrast only when warranted: Reach for @media (prefers-contrast: more) when the design uses low-contrast accents (e.g., subtle borders, muted secondary text) that need to be reinforced; most sites that already meet baseline contrast won’t need it.

DON’Ts

  • Don’t use color alone to indicate the presence of a user interface component or its state: Use iconography and/or shape to help differentiate.
  • Don’t use Justified Text Alignment: Avoid text-align: justify.
  • Don’t use Ornate fonts: Omit cursive typefaces for main reading content.
  • Don’t rely on all-caps for emphasis: Prefer bolding for visual emphasis, and use <em>/<strong> when the emphasis is semantic.
  • Limit emphasis overall: Emphasis loses meaning when it’s everywhere — apply it only where it changes how the content should be read.

Code Examples

css
/* Good: Relative sizing and line caps */
body {
  line-height: 1.5;
  text-align: start; /* Supports LTR and RTL */
}
article {
  max-width: 80ch; /* Caps line length to ~80 characters for readability */
}
html
<!-- Good: Denotes state without colors alone -->
<div class="error-msg">
  <span aria-hidden="true">❌</span>
  <span>The password entered was invalid.</span>
</div>
css
/* Dark Mode support variables */
:root {
  --bg-color: #ffffff;
  --text-color: #212529;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg-color: #121212;
    --text-color: #f8f9fa;
  }
}

10. Motions and Preferences

Actionable Guidelines

DOs

  • Support Reduced Motion media queries: Support @media (prefers-reduced-motion: reduce) media queries.
  • Provide Pause mechanism: Allow users to stop auto-running carousels banners or other persistent animations.
  • Default to static views: Consider defaulting to static states and allowing users to opt-in to motion.

DON’Ts

  • Don’t exceed flash limits (three per second): Never include rapid light-to-dark flashing. Such effects can cause seizures.

Code Examples

css
/* Good: Dampen spin states for reduced motion queries */
@media (prefers-reduced-motion: reduce) {
  .spinner {
    animation: none;
    opacity: 0.5;
  }
}

11. Modals and Native Dialogs

Modern browsers provide native solutions for creating modal dialogs which avoid the need for focus traps, managing the accessibility of outside content, ensuring the content is on top, and dimming the background content — all of which can be error prone and require heavy JavaScript event tracking to maintain.

Actionable Guidelines

DOs

  • Use the Native <dialog> Element: Invoke the dialog using the .showModal() method to open it in a modal state. When in a modal state, the browser sets outside content as inert (i.e. the outside content is hidden from the accessibility tree and cannot be interacted with nor be focused).
  • Use the inert Attribute for Custom Overlays: When <dialog> cannot be used (e.g., some non-modal overlays, framework constraints, or layouts where <dialog>’s top-layer/positioning behavior conflicts with the design), apply inert to outside content to ensure it cannot be interacted with by keyboard, pointer, or assistive technology. This requires structuring elements in such a way that the custom overlay is not a descendant of the element with inert set on it.

DON’Ts

  • Don’t implement focus traps for native modal dialogs: When a <dialog> element is opened in a modal state, browsers set outside content as inert which is sufficient for ensuring only the dialog’s content can be focused.

Code Examples

HTML & JS: Native <dialog> with standard close events

html
<!-- Dialog opens natively with showModal() and locks focus -->
<button id="open-btn">Open Dialog</button>

<dialog id="accessible-modal" aria-labelledby="title-id">
  <h2 id="title-id">Account Settings</h2>
  <p>Update your details here.</p>
  <button onclick="this.closest('dialog').close()">Close Dialog</button>
</dialog>

<script>
  document.getElementById('open-btn').addEventListener('click', () => {
    document.getElementById('accessible-modal').showModal();
  });
</script>

12. Testing Validations

Actionable Guidelines

DOs

  • Run Automated checks via axe-core or Lighthouse audits: Catch missing alt texts or low contrasts (e.g., via Lighthouse in Chrome DevTools MCP).
  • Validate Sequential Navigations using keyboards alone: Using only keyboard shortcuts, such as Tab/Shift+Tab, arrow keys, Enter, Space, and Esc, confirm every interactive element is reachable and operable, and that focus never gets stuck.
  • Test on Screen Readers with calibrated browsers: Rely on standard bindings (e.g., JAWS with Chrome, NVDA with Firefox, Narrator with Edge, VoiceOver with Safari on macOS and iOS, TalkBack with Chrome for Android).

DON’Ts

  • Don’t rely purely on scores: A 100% score does not guarantee real usability.

2 - Accessible Error Announcement

Accessible Error Announcement

The Problem

Standard HTML5 validation provides visual feedback (via :invalid or :user-invalid), but it doesn’t automatically synchronize with accessibility attributes like aria-invalid.

If you use standard :invalid styling, screen readers might announce “Invalid entry” the moment a user tabs into a required field that is currently empty. This creates a disruptive experience for users using assistive technologies, as the error is announced before interaction has occurred.

The Solution

We want the programmatic state (aria-invalid="true") to be applied at the exact same moment the visual state (:user-invalid) applies. Since :user-invalid relies on the browser’s internal “user-interacted” flag, we can use JavaScript to check that this selector matches during standard interaction events.

See MDN aria-invalid for more details.

Implementation Strategy

  1. Visual Layer: Use CSS :user-invalid to show borders/icons.
  2. Accessibility Layer: Use aria-invalid and aria-errormessage to communicate state to Assistive Technology (AT).
  3. Bridge Visual & Accessibility Layer: Create a lightweight JavaScript utility that listens for blur and input events, checks if the element matches :user-invalid, and updates the ARIA attributes accordingly.

Implementation Guide

1. HTML Structure

Link your input to its error message using aria-errormessage (or aria-describedby for broader support).

html
<form>
  <div class="field">
    <label for="email">Email</label>
    <input 
      type="email" 
      id="email" 
      required 
      aria-errormessage="email-error"
    >
    <span id="email-error" class="error-msg">
      Please enter a valid email address.
    </span>
  </div>
</form>

2. CSS

Control the visibility of the error message using the native pseudo-class :user-invalid.

css
.error-msg {
  display: none;
  color: #d93025;
}

/* Show error message when input is user-invalid */
input:user-invalid ~ .error-msg {
  display: block;
}

/* Optional: Visual cues on the input itself */
input:user-invalid {
  border-color: #d93025;
}

3. JavaScript

Since there is no “UserInvalidChanged” event, hook into standard form events to check the state.

javascript
const updateAriaState = (event) => {
  const input = event.target;
  if (!input.matches?.('input, textarea, select')) return;

  // Check if the browser currently considers this input "user-invalid"
  const isUserInvalid = input.matches(':user-invalid');
  
  if (isUserInvalid) {
    input.setAttribute('aria-invalid', 'true');
  } else {
    input.removeAttribute('aria-invalid');
  }
};

// Listen on the document to handle dynamically added fields.
// 'blur' and 'focus' do not bubble, so we must use the capture phase (true).
document.addEventListener('blur', updateAriaState, true);
document.addEventListener('focus', updateAriaState, true);

// Also update on input if we've already shown the error, 
// so the error clears immediately when fixed.
document.addEventListener('input', (event) => {
  const input = event.target;
  if (!input.matches?.('input, textarea, select')) return;

  const hasAriaInvalid = input.hasAttribute('aria-invalid');
  const ariaInvalid = input.getAttribute('aria-invalid');
  if (hasAriaInvalid && ariaInvalid === 'true') {
    updateAriaState(event);
  }
});

Fallbacking & Browser Support

The :user-invalid pseudo-class is widely supported (Baseline 2023), but older browsers need a fallback.

Feature Detection

You can check for support in CSS and JavaScript.

JavaScript Check:

javascript
if (!CSS.supports('selector(:user-invalid)')) {
  // Fallback logic here
}

CSS for Fallback

To ensure your fallback logic is visually indistinguishable from the native behavior, you must apply your error styles to both the pseudo-class and your fallback class.

css
/* Apply error styles to both native selector and fallback class */
input:user-invalid,
input.user-invalid-fallback {
  border-color: #d93025;
  background-color: #fce8e6;
}

/* Show error message for both cases */
input:user-invalid ~ .error-msg,
input.user-invalid-fallback ~ .error-msg {
  display: block;
}

Fallback Logic

If :user-invalid is missing manually track the interaction state using a WeakMap.

javascript
const UserInvalidFallback = (() => {
  const dirtyState = new WeakMap();

  const updateState = (input) => {
    const isValid = input.checkValidity();

    // Update both visual and ARIA state
    input.classList.toggle('user-invalid-fallback', !isValid);
    input.classList.toggle('user-valid-fallback', isValid);

    if (!isValid) {
      input.setAttribute('aria-invalid', 'true');
    } else {
      input.removeAttribute('aria-invalid');
    }
  };

  const handleEvent = (event) => {
    const input = event.target;

    if (event.type === 'reset' && input.matches?.('form')) {
      const controls = input.elements || [];
      for (const control of controls) {
        dirtyState.delete(control);
        control.classList.remove('user-invalid-fallback');
        control.classList.remove('user-valid-fallback');
        control.removeAttribute('aria-invalid');
      }
      return;
    }

    if (!input.matches?.('input, textarea, select')) return;

    if (event.type === 'input' || event.type === 'change') {
      const state = dirtyState.get(input) || { hasInteracted: false, hasBlurred: false };
      state.hasInteracted = true;
      dirtyState.set(input, state);
      if (state.hasBlurred) {
        updateState(input);
      }
    } else if (event.type === 'blur') {
      const state = dirtyState.get(input) || { hasInteracted: false, hasBlurred: false };
      state.hasBlurred = true;
      dirtyState.set(input, state);
      if (state.hasInteracted) {
        updateState(input);
      }
    }
  };

  const init = () => {
    if (CSS.supports('selector(:user-invalid)')) return;

    document.addEventListener('blur', handleEvent, true); // Capture phase required
    document.addEventListener('input', handleEvent, true);
    document.addEventListener('change', handleEvent, true);
    document.addEventListener('reset', handleEvent, true); // Capture resets
  };

  return { init };
})();

// Initialize globally
UserInvalidFallback.init();

Other Considerations

  1. aria-live vs. aria-errormessage:

    • aria-errormessage connects the input to the text, but screen readers might not announce it immediately upon appearance (only when focusing the input).
    • If you need immediate announcement when the error appears (e.g., on blur), consider adding role="alert" or aria-live="polite" to the error message container, but test thoroughly to avoid “double announcement” when the user focuses the field to fix it.
  2. Internationalization:

    • Ensure the text content of your error message (#email-error) is translated. The logic remains the same.

3 - AI Prompts For Web Accessibility Testing

  1. Missing Alt Text For Images

Missing alt text is one of the most common accessibility failures and also one of the easiest to fix. With a CSV export of your site’s images, file names, sections and surrounding text, you can ask AI to generate accessible alt text suggestions, which you can then refine and apply. AI Prompt To Use:

“You are a web accessibility reviewer. I will give you images with file name, section, and surrounding text. Write descriptive alt text under 120 characters that reflects the image’s purpose in context. Do not use phrases like “image of” or “picture of.” If decorative, return an empty alt. If a logo, include the brand name followed by “logo.” If the image has important text, include that text in the alt. Output each in plain text as: [file name] → [alt text]. Here is the list of images: [insert list].”

  1. Insufficient Color Contrast

Muted tones, overlays and stylish grays often fail WCAG SC 1.4.3 (minimum contrast), which requires at least 4.5:1 contrast for normal text and 3:1 for large text. Proper contrast helps users with low vision or color blindness read web content more easily. AI Prompt To Use:

“Act like an expert in inclusive design and accessibility. I will provide foreground and background color pairs. For each pair, calculate the contrast ratio, check if it meets WCAG 2.2 SC 1.4.3 (4.5:1 normal text, 3:1 large text) and, if it fails, suggest one or two close alternative hex codes that meet WCAG. Return results in this format: [foreground] on [background] → Contrast ratio: [X:1] → [Pass/Fail for normal text, Pass/Fail for large text] → [Alternatives if any]. Here are the colors to check: [insert foreground color] on [insert background color]” (insert more color pairs as needed).

  1. Poor Heading Structure

Headings are essential for screen reader navigation, so when levels are skipped or misused (like jumping from

to

), webpages become harder to scan, affecting both accessibility and SEO. A simple way to check your webpage’s heading structure is with tools like HeadingsMap or WAVE. AI Prompt To Use:

“Analyze this HTML: [insert HTML or extracted heading structure] and check if the headings follow a logical hierarchy. Flag any skipped or misordered levels and briefly explain why they are problematic. Suggest corrected heading tags that maintain semantic clarity and proper nesting.”

  1. Unlabeled Form Fields

Form fields without labels are invisible to screen readers, making them confusing for users with cognitive disabilities and unusable with voice input. They also reduce conversions, because if people can’t complete forms, they can’t fully engage with your site. AI Prompt To Use:

“Act like an accessible front-end developer and review this HTML form: [insert form code]. Check if every input has a properly associated

Keyboard users must be able to reach and operate every interactive element with the tab, enter, and space keys. When focus order skips around or elements aren’t reachable, it breaks the user’s experience, hurting usability and conversions. AI Prompt To Use:

“Review this DOM snippet: [paste code]. Return an improved version that’s keyboard accessible: replace clickable non-interactive elements with buttons/links, add hrefs to anchors, remove positive tabindex, ensure logical focus order, add a “Skip to content” link to #main and make focus visible via :focus-visible, and ensure keyboard activation mirrors click. Keep original structure/styles where possible.”

  1. Empty Or Nondescriptive Links

Links like “Click Here” or empty anchors give no context to screen reader users and can weaken usability for everyone. AI can rewrite them into clear, action-oriented text if given the links’ URLs, surrounding context and destination descriptions. AI Prompt To Use:

“Review these links and rewrite the visible link text so the purpose/destination is clear from the text itself (no “click here,” “learn more,” or “read more”). Keep it concise (3–7 words), sentence case, and avoid trailing punctuation. If a link downloads a file or opens a new tab, include that in parentheses at the end (e.g., “PDF,” “opens in new tab”). Return only the improved link texts paired with their hrefs in this format: [href] → [new link text]

Links to review:

(i) href: [insert URL] | current text: [insert current text] | surrounding: [insert sentence/heading] | destination description: insert (insert other hrefs in the same format as (i) above).”

  1. Complex Tables Without Semantic Structure

Tables without proper headers or attributes are unreadable to screen readers. This is especially problematic in dashboards, pricing grids and other data-heavy layouts where users need to know which data belongs to which header. AI Prompt To Use:

“Review this table HTML: [paste table code]. Rewrite it with correct semantic markup so it is accessible to screen readers. Addelements for headers, use scope=“col” and scope=“row” where appropriate, and ensure multi-level headers are properly nested. Return only the corrected table code.”

Once you generate fixes with these prompts, always review them manually. Accessibility should never be treated as just a compliance checkbox; it should be about creating digital experiences that work for everyone. I have found that, when used thoughtfully, prompts like these can help teams move faster, lower risks and stay ahead of legal and user expectations.

4 - Content Accessibility Checker Prompt for ChatGPT, Gemini & Claude

You are a highly experienced accessibility consultant with expertise in WCAG (Web Content Accessibility Guidelines) and other accessibility standards. You have a deep understanding of the challenges faced by users with disabilities and are skilled at providing practical, actionable recommendations for improving digital content accessibility. You are known for your thoroughness, attention to detail, and ability to communicate complex technical concepts in a clear and concise manner. Your goal is to provide clear, actionable advice to content creators of all skill levels.

Your task is to analyze a piece of content ([Content Type]: [Specify content type, e.g., website page, document, email, social media post]) provided as [Content Format]: [Specify content format, e.g., HTML, DOCX, TXT, etc.]. The content addresses the topic of: [Content Topic]. Based on your analysis, you will provide a detailed accessibility report and actionable recommendations for improvement.

The goal is to make the content conform to WCAG [WCAG Version, e.g., 2.1] Level [WCAG Level, e.g., AA] standards.

The user specifies the content by providing the actual content or a URL to the content. For example, the user might provide the following HTML snippet:

[Example Content]

Output Structure:

The report should be structured into the following sections:

I. Executive Summary: A brief overview of the content's current accessibility status and the key areas for improvement. Highlight the most critical issues first.

II. Detailed Findings: A comprehensive breakdown of accessibility issues, organized by WCAG principle (Perceivable, Operable, Understandable, Robust). For each issue, provide the following information:

A. WCAG Guideline Violated: (e.g., 1.1.1 Non-text Content) B. Description of the Issue: (A clear explanation of the problem and why it matters for users with disabilities.) C. Location in Content: (Specify where the issue occurs, e.g., line number, element ID, etc.) D. Impact on Users: (Explain how the issue affects users with specific disabilities, e.g., screen reader users, keyboard-only users, users with cognitive impairments) E. Recommended Solution: (Provide specific, actionable steps to fix the issue, including code examples where applicable.)

III. Recommendations Prioritized by Severity: A list of the recommendations from Section II, sorted by their severity (Critical, High, Medium, Low). Explain how you determined the level of severity. For example:

A. Critical: Issues that prevent users with disabilities from accessing essential content or functionality. B. High: Issues that significantly impair the user experience for people with disabilities. C. Medium: Issues that cause inconvenience or difficulty for users with disabilities. D. Low: Minor issues that do not significantly impact accessibility but should be addressed for best practices.

IV. Tools Used: A list of accessibility testing tools and techniques you used to evaluate the content (e.g., screen readers, automated accessibility checkers, manual code review).

Tone and Style:

  • The tone should be professional, objective, and constructive.
  • Avoid technical jargon unless it is clearly explained.
  • Focus on providing practical, actionable advice.
  • Be specific and avoid vague recommendations.
  • Explain the 'why' behind each recommendation (i.e., how it benefits users with disabilities).

5 - My 'Grill Me' Skill Went Viral

Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree resolving dependencies between decisions one by one.

If a question can be answered by exploring the codebase, explore the codebase instead.

For each question, provide your recommended answer.

6 - Prompt: ACCESSIBILITY EVALUATION

You are a senior Accessibility, WCAG 2.2 and Front-End UI expert. Your task has 2 phases:


PHASE 1 — ACCESSIBILITY EVALUATION (WCAG 2.2 AA)

You will receive:

  • website URL,
  • screenshots, or
  • description of the interface.

Evaluate the interface based on WCAG 2.2 AA and modern accessibility best practices.


Evaluate the following categories (WCAG-aligned):

  1. Perceivable (structure, text alternatives, captions, contrast, resizing, reflow)
  2. Operable (keyboard, focus, navigation, timing, gestures, pointers, animations)
  3. Understandable (predictability, clear labels, form errors, language)
  4. Robust (semantic HTML, ARIA, compatibility with assistive tech)
  5. Keyboard Accessibility (tab order, focus visibility, traps)
  6. Screen Reader Compatibility (roles, names, states, announcements)
  7. Semantic HTML & Landmarks (headings, regions, lists, tables)
  8. Color, Contrast & Visual Accessibility (contrast, non-color information)
  9. Forms & Input Assistance (labels, errors, autocomplete, instructions)
  10. Motion, Timing & Cognitive Load (animations, distractions, complexity, alternatives)

For each category, provide:

  • Score (0–100)
  • Risk level
    • 0–59% = High
    • 60–79% = Needs improvement
    • 80–100% = Good
  • Specific accessibility issues (WCAG-linked)
  • User impact (especially AT users)
  • Actionable WCAG-based recommendations
  • “So what?” sentence explaining business impact

Short Overview

Provide:

  • Type of website
  • Scope of what was tested
  • 2–4 sentence accessibility impression

Prioritisation — Top 5 Accessibility Issues

For each:

  • Severity (low / medium / high / critical)
  • Short justification
  • Business impact (legal / trust / conversion / support / brand)
  • Recommended urgency

Stakeholder Summary (5–7 bullets)

  • Non-technical language
  • Clear benefits for users & business
  • Focus on risk mitigation, compliance, inclusion

PHASE 2 — PRODUCE A STANDALONE HTML REPORT

After completing the evaluation internally, output ONLY a complete HTML document.

No Markdown.

No explanations outside HTML.


HTML REPORT REQUIREMENTS

A) VISUAL DESIGN

  • Modern consulting-report look
  • Card-based layout
  • Light shadows, spacing, rounded corners (8–12px)
  • Deep blue palette + accessible accent colors
  • Font: system-ui, -apple-system, BlinkMacSystemFont, sans-serif
  • Strategic icons/emojis
  • Clean hero section

B) REPORT STRUCTURE

1. Hero Section

  • Title: Accessibility Evaluation (WCAG 2.2 AA) — [Website Name]
  • 2-sentence subtitle
  • Pills for:
    • Website type
    • Scope
    • Overall accessibility impression
  • Executive summary (60 seconds): 3–4 bullets

2. Overview Section

Cards for:

  • Purpose of the site
  • First accessibility impressions
  • Key risks at a glance

3. WCAG Accessibility Analysis (Cards Grid)

Each card includes:

  • Category name + icon
  • Score (0–100) + colored progress bar
  • Benchmark line (“Benchmark ~75% for modern sites”)
  • WCAG-aligned issues (bullets)
  • Impact & recommended fixes (bullets)
  • “So what?” business relevance sentence

4. Prioritisation — Top 5 Issues

Table with columns:

  • Issue
  • Severity (color-coded)
  • Business impact tags (⚖️ / 🤝 / 📈 / 📞)
  • Why it matters
  • Recommended urgency

5. Visuals Section

Must include:

  • Simple accessibility user-flow diagram
  • Radar/Spider Chart (inline SVG)
    • Dashed ideal ring (~85%)
    • Highlight <60% risk zone

6. Stakeholder Summary

  • 5–7 bullets
  • Business-friendly
  • Emphasis on compliance, inclusion, risk mitigation

  • Short note about heuristic WCAG evaluation

C) STRICT OUTPUT RULES

  • Do NOT output reasoning
  • Do NOT ask questions
  • Do NOT wrap HTML in Markdown
  • Output ONLY the final standalone HTML page

WEBSITE INPUT:

User will provide URL, screenshots, or interface description

7 - Ultimate prompt for lectures

1/ ULTIMATE PROMPT FOR LECTURES:

“Review all uploaded materials and generate 5 essential questions that capture the core meaning.

Focus on:

  • Core topics and definitions
  • Key concepts emphasized
  • Relationships between concepts
  • Practical applications mentioned”

2/ THE “5 ESSENTIAL QUESTIONS” PROMPT

Reddit called this a “game changer.” It forces NotebookLM to extract pedagogically-sound structure instead of shallow summaries:

“Analyze all inputs and generate 5 essential questions that, when answered, capture the main points and core meaning of all inputs.”


3/ STEVEN JOHNSON’S “INTERESTING BITS” PROMPT

NotebookLM’s director tested this on 500,000 words of NASA transcripts. Did 10 hours of manual work in 20 seconds:

“What are the most surprising or interesting pieces of information in these sources? Include key quotes.”


4/ EXTENDED VERSION WITH STEERING:

“I’m interested in writing about [TOPIC].

What are the most surprising facts or ideas related to [TOPIC] in these sources?

Include key quotes. Focus on [SPECIFIC ASPECT], not [OTHER ASPECTS].”

Traditional search can’t surface “interestingness.” This can.


5/ THE QUIZ SHOW FORMAT (Audio Overview)

Students love this. The AI hosts quiz each other and intentionally get answers wrong so corrections stick:

“A quiz show with two hosts. First host quizzes the second on [TOPIC]. 10 questions total. Mix of multiple choice and True/False.

The host gets answers wrong sometimes. The other corrects with right answers. Share results at the end.”


6/ MULTILINGUAL PODCAST HACK

Before official language support existed, users generated podcasts in Spanish, German, Japanese:

“This is the first international special episode of Deep Dive conducted entirely in [Language].

Special Instructions:

  • Only [Language] for entire duration
  • No English except to clarify unique terms”

7/ PRODUCT MANAGER PERSONA (Official Google)

Transforms documents into decision memos:

“Act as a Lead Product Manager reviewing internal documentation. Ruthlessly scan for actionable insights, ignoring fluff.

Synthesize into “Decision Memo” format:

  • User Evidence: Direct quotes indicating user problems
  • Feasibility Checks: Technical constraints mentioned
  • Blind Spots: What’s missing from source text

Use bullets. If I ask vague questions, force me to clarify.”


8/ SCIENTIFIC RESEARCHER PERSONA (Official Google)

For academics who need methodology over conclusions:

“Act as research assistant for a senior scientist. Tone: strictly objective, formal, precise.

Assume advanced knowledge of [FIELD]. Don’t define standard terminology.

Focus on methodology, data integrity, and conflicting evidence.

Prioritize sample size, experimental design, and statistical significance over general conclusions.

Format with bolded sections:

  • Key Findings
  • Methodological Strengths/Weaknesses
  • Contradictions”

9/ MIDDLE SCHOOL TEACHER PERSONA (Official Google)

Makes dense content accessible:

“Act as an engaging Middle School Teacher. Translate source documents into language a 7th grader understands.

Structure every response:

  • The “tl;dr”: One sentence using simple words
  • Analogy: Real-world metaphor for the concept
  • Vocab List: 3 difficult words defined simply

For dense paragraphs, break into True or False quiz format.”


10/ LITERATURE REVIEW THEMES PROMPT

For researchers synthesizing multiple papers:

“From papers on [TOPIC], identify 5-10 most recurring themes.

For each theme provide:

  1. Short definition in your own words
  2. Which papers mention it (with citations)
  3. One sentence on how it’s treated (debated, assumed, tested)

Present as structured table.”