Sa11y Accessibility Assistant

repository·master·Indexed 43 days ago

https://github.com/ryersondmp/sa11y

A customizable, framework-agnostic JavaScript plugin for accessibility quality assurance. Sa11y acts as a visual, in-page checker that highlights common accessibility and usability issues for content authors, providing simple tooltips on how to fix errors at the source. Version 5.0.9 supports web components, shadow DOM, and headless checks.

Tokens
4.3K
Snippets
8
Records
20
Agent score
55%

What's inside Sa11y

  1. Overview of Sa11y accessibility assistant

    master

    Sa11y is a customizable, framework-agnostic JavaScript plugin designed for accessibility quality assurance. It functions as an in-page checker that visually highlights common accessibility and usability issues directly on the page.

    Key Characteristics:

    • Target Audience: Geared towards content authors by providing simple tooltips on how to fix identified errors.
    • Scope: It is not a comprehensive code analysis tool; it focuses exclusively on highlighting content issues.
    • Automation: Automatically checks content on page load.
    • Customization: Uses JSON-like props to fine-tune the experience and allows turning off or hiding irrelevant checks.
    • Capabilities: Supports checking items within web components/shadow DOM and headless checks.
    • UI: Features a fully encapsulated user interface with dark mode support and multi-language availability.
  2. Configure Playwright for Sa11y conformance testing

    master

    The conformance/playwright.config.js file defines the environment for running Playwright tests used in Sa11y's conformance suite. It configures the test directory, execution timeouts, reporters, and a local web server to host test cases.

    Key configuration settings include:

    • testDir: Set to ./tests.
    • timeout: Set to 500ms.
    • workers: Set to 4 parallel workers.
    • reporter: Generates a list reporter and a json reporter saved to ./reports/playwright-results.json.
    • use: Configures the baseURL to http://localhost:8844, runs in non-headless mode (headless: false), and uses the chromium browser.
    • webServer: Automatically starts the test environment using the command node conformance/scripts/serve-testcases.js on port 8844 before running tests.
    import { defineConfig } from '@playwright/test';
    import { dirname, join } from 'node:path';
    import { fileURLToPath } from 'node:url';
    
    const __dirname = dirname(fileURLToPath(import.meta.url));
    const projectRoot = join(__dirname, '..');
    
    export default defineConfig({
      testDir: './tests',
      timeout: 500,
      retries: 0,
      workers: 4,
      reporter: [
        ['list'],
        ['json', { outputFile: './reports/playwright-results.json' }],
      ],
      use: {
        baseURL: 'http://localhost:8844',
        headless: false,
        browserName: 'chromium',
      },
      webServer: {
        command: 'node conformance/scripts/serve-testcases.js',
        port: 8844,
        reuseExistingServer: true,
        cwd: projectRoot,
      },
    });
  3. Configure Playwright for Sa11y testing

    master

    The project uses Playwright for its testing suite. The playwright.config.js file defines the test directory, parallelization settings, and browser projects. When running in a CI environment, the configuration automatically adjusts retry logic, worker counts, and forbids the use of test.only to ensure build stability.

    import { defineConfig, devices } from '@playwright/test';
    
    export default defineConfig({
      testDir: './test',
      fullyParallel: true,
      forbidOnly: !!process.env.CI,
      retries: process.env.CI ? 2 : 0,
      workers: process.env.CI ? 1 : undefined,
      use: {
        baseURL: 'http://localhost:8080',
        trace: 'on-first-retry',
      },
      testIgnore: '**/src/**',
      projects: [
        { name: 'chromium', use: { ...devices['Desktop Chrome'] } },
        { name: 'firefox', use: { ...devices['Desktop Firefox'] } },
        { name: 'webkit', use: { ...devices['Desktop Safari'] } },
      ],
    });
  4. Manage DOM element clones and previews

    master

    For advanced UI tasks like generating issue reports or cloning parts of the DOM:

    • fnIgnore(element, selectors): Creates a clone of an element while excluding specific tags (defaulting to noscript, script, style, audio, video, form, iframe) or any additional selectors provided.
    • generateElementPreview(issueObject, convertBase64): Generates a DOM node preview for an issue. For <img> tags, it can optionally fetch the image and convert it to a Base64 string to ensure the preview is self-contained.
  5. Retrieve and clean text content

    master

    Use these utilities to extract clean text from DOM nodes:

    • getText(element): Retrieves the textContent of an element, but uses fnIgnore to skip elements like <script> or <style>, and normalizes whitespace/line breaks. It uses an internal WeakMap to cache results for performance.
    • removeWhitespace(string): Collapses multiple whitespace characters into a single space and trims the string.
    • normalizeString(string): Removes non-printable ASCII control characters and extra whitespace.
  6. Utility: Debounce, Store, and CSS Helpers

    master

    Standard developer utilities included in the package:

    • debounce(callback, wait): Returns a debounced version of the provided callback.
    • store: A utility object for interacting with localStorage and sessionStorage. store.getItem(key) attempts to fetch from localStorage first, falling back to sessionStorage if not found.
    • getCachedStyle(node, pseudoElt): Returns the computed style of a node, using a WeakMap to cache results and avoid redundant getComputedStyle calls.
    • supportsAnchorPositioning(): Checks if the browser supports the CSS Anchor Positioning API.
  7. Generate a SHA-256 digest with dismissDigest()

    master

    The dismissDigest function generates a lowercase hexadecimal SHA-256 digest from a combination of a pepper (a secret or application-specific salt) and a message (an identifier). This is primarily used to create unique, stable keys for dismissing accessibility messages within localStorage.

    import { dismissDigest } from './utils';
    
    const digest = await dismissDigest('my-secret-pepper', 'accessibility-error-id-123');
    // returns a lowercase hex string
  8. Determine if an element is hidden and unfocusable

    master
    The isHiddenAndUnfocusable($el) function checks if an element is properly neutralized for both Assistive Technology (AT) and keyboard users. It returns true if the element is either presentational (role="presentation" or role="none") or aria-hidden="true", AND it has a negative tabindex.
  9. Access Sa11y audit results and found elements

    master

    The Sa11y instance provides two primary getters for inspecting the state of an accessibility audit:

    • results: Returns the main array of audit results stored in the internal State.
    • elements: Returns the collection of elements identified by the tool (via Found.Found).
  10. Extract pseudo-element content with wrapPseudoContent()

    master

    The wrapPseudoContent utility extracts text content from an element's :before and :after pseudo-elements and wraps a provided string with them.

    Parameters:

    • element (Element): The target DOM element.
    • string (string): The base string to wrap with pseudo-element content.

    Returns:

    • string: A string formatted as [before-content][string][after-content].

    Note on Content Extraction: It specifically looks for text within quotes in the CSS content property. For example, if a pseudo-element has content: "icon";, it extracts icon.

    import { wrapPseudoContent } from './path/to/computeAccessibleName';
    
    // If :before { content: "★"; } and :after { content: " text"; }
    const result = wrapPseudoContent(element, 'Hello');
    // result would be "★Hello text"
  11. Initialize Sa11y using the Sa11y class

    master

    To use Sa11y, instantiate the Sa11y class with an options object. The constructor sets the initial state via setState and runs the initialize() routine. Upon instantiation, the Sa11y instance exposes several utility methods directly on itself, including checkAll, resetAll, find, enabled, and disabled, as well as all methods from the Utils module.

    Use the results getter to access the main array of accessibility audit results and the elements getter to access the list of elements found during the audit.

    import { Sa11y } from './js/sa11y';
    
    const sa11y = new Sa11y({
      // pass your configuration options here
    });
    
    // Access audit results
    console.log(sa11y.results);
    
    // Access found elements
    console.log(sa11y.elements);
    
    // Use exposed utility methods
    sa11y.checkAll();