npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

eslint-plugin-aria-state-validator

v1.1.1

Published

Comprehensive ESLint plugin for ARIA accessibility validation: dynamic state binding and static ARIA attributes correctness

Downloads

119

Readme

eslint-plugin-aria-state-validator

Comprehensive ESLint plugin for ARIA accessibility validation:

  • Dynamic State Validation: Validates that ARIA state attributes are properly bound to component state
  • Static ARIA Validation: Validates static ARIA attributes for correctness (spelling, values, conflicts)

Catches both runtime and static accessibility errors at build time.

Problem Statement: The "Runtime Gap" in Static Analysis

Existing accessibility tools like eslint-plugin-jsx-a11y validate the syntactic correctness of ARIA attributes (e.g., ensuring aria-expanded uses 'true' or 'false'), but they cannot verify whether these attributes are correctly connected to the component's JavaScript state and dynamically updated at runtime.

Issues This Causes:

  • Toggle buttons with aria-expanded="false" hardcoded, never changing when opened
  • Boolean values directly bound to ARIA attributes: aria-expanded={isOpen} (incorrect - should be string)
  • Static ARIA states on interactive elements that should be dynamic
  • Screen readers receiving inaccurate information about component states

Core Concept: State-Dependent ARIA Validation

This plugin uses AST (Abstract Syntax Tree) analysis to statically verify that ARIA state attributes are logically connected to component state (State/Props) and will update dynamically at runtime.

Key Differentiator

Goes beyond syntax checking to infer component dynamic behavior, proactively catching runtime accessibility errors during build/CI phase.

Installation

npm install --save-dev eslint-plugin-aria-state-validator

Usage

ESLint Flat Config (ESLint 9+)

// eslint.config.js
import ariaStateValidator from 'eslint-plugin-aria-state-validator';

export default [
  ...ariaStateValidator.configs['flat/recommended']
];

Available flat presets:

  • flat/recommended
  • flat/strict
  • flat/dynamic-only
  • flat/static-only

Legacy ESLintRC Config

{
  "plugins": ["aria-state-validator"],
  "rules": {
    "aria-state-validator/state-dependent-aria-validator": "warn"
  }
}

Two Rules for Comprehensive ARIA Validation

This plugin provides two complementary rules:

Rule 1: state-dependent-aria-validator (Dynamic State Validation)

Validates that ARIA state attributes are properly bound to component state and update dynamically.

Rule options:

  • interactiveHandlers (string[]): Override which event props are treated as interactive (default: onClick, onKeyDown, onKeyPress, onChange, onToggle)
  • strictBooleanInference (boolean): When true (default), only flags identifiers inferred as boolean-like; when false, treats any identifier binding as boolean-risk
  • ignorePatterns (string[]): Regex patterns to skip checks for matching attribute names or value source text

Example:

{
  rules: {
    'aria-state-validator/state-dependent-aria-validator': ['warn', {
      interactiveHandlers: ['onClick', 'onPointerDown'],
      strictBooleanInference: true,
      ignorePatterns: ['^aria-current$', '^\\{isOpen\\}$']
    }]
  }
}

Rule 2: static-aria-validator (Static ARIA Validation)

Validates the correctness of ARIA attributes when they are used:

  • Valid ARIA property names (catches typos with auto-fix)
  • Correct values for boolean and enum ARIA attributes (auto-fix for "yes"/"no")
  • No conflicting ARIA attributes (auto-fix available)
  • No redundant roles on native HTML elements (auto-fix available)
  • Required ARIA attributes based on roles (e.g., aria-checked for switch)
  • Role-attribute compatibility (e.g., prevents aria-expanded on img)

Note: This plugin validates how ARIA attributes are used, not whether they should be used. For enforcing the presence of accessibility features, use eslint-plugin-jsx-a11y.

Features & Validation Patterns

1. Boolean Value Direct Binding Detection

Detects: Direct binding of Boolean values to ARIA attributes

// ❌ Error: Boolean value directly bound
<button aria-expanded={isOpen}>Toggle</button>

// ✅ Correct: Explicit string conversion
<button aria-expanded={isOpen ? 'true' : 'false'}>Toggle</button>

Suggestion Available: The rule provides a safe suggestion to convert bindings to string format ('true'/'false').

2. Static Value + Interactive Handler Detection

Detects: Static ARIA state values on elements with event handlers

// ❌ Error: Has onClick but aria-expanded is static
<button onClick={handleClick} aria-expanded="false">
  Toggle
</button>

// ✅ Correct: Dynamic state binding
<button onClick={handleClick} aria-expanded={isOpen ? 'true' : 'false'}>
  Toggle
</button>

Smart Suggestion: When the handler contains state variable references (e.g., () => setExpanded(!expanded)), the plugin can suggest binding the inferred variable to the ARIA attribute:

// ❌ Before suggestion
<div onClick={() => setExpanded(!expanded)} aria-expanded="false">
  Click to expand
</div>

// ✅ Suggested fix (automatically detects 'expanded' variable)
<div onClick={() => setExpanded(!expanded)} aria-expanded={expanded ? 'true' : 'false'}>
  Click to expand
</div>

Supported Patterns for Suggestions:

  • () => setX(!x)
  • () => setX(true)
  • () => setX(prev => !prev)

3. Role-Based State Association Validation

Detects: Interactive roles with static ARIA states or missing required states.

// ❌ Error: role="button" with static aria-pressed
<div role="button" aria-pressed="false">Button</div>

// ❌ Error: interactive switch role missing aria-checked
<div role="switch" onClick={toggle}>Toggle</div>

// ✅ Correct: Dynamic state binding
<div role="button" aria-pressed={isPressed ? 'true' : 'false'}>Button</div>
<div role="switch" aria-checked={isChecked ? 'true' : 'false'}>Toggle</div>

Static ARIA Validation Patterns

4. Invalid ARIA Property Detection

Detects: Typos in ARIA attribute names

// ❌ Error: Typo in aria-label
<button aria-labell="Close">X</button>

// ✅ Correct (Auto-fixed): Proper spelling
<button aria-label="Close">X</button>

5. Empty Required Values

Detects: ARIA attributes that require non-empty values

// ❌ Error: Empty aria-label
<div aria-label="">Content</div>

// ✅ Correct: Non-empty value
<div aria-label="Description">Content</div>

6. Invalid Boolean Values

Detects: Incorrect boolean-like values

// ❌ Error: Invalid boolean value (Auto-fix available for "yes"/"no")
<div aria-hidden="yes">Content</div>
<div aria-disabled="1">Content</div>

// ✅ Correct: Use "true" or "false"
<div aria-hidden="true">Content</div>
<div aria-disabled="false">Content</div>

7. Invalid Enum Values

Detects: Invalid values for enum-type ARIA attributes

// ❌ Error: Invalid aria-live value
<div aria-live="loud">Live region</div>

// ✅ Correct: Use valid enum value
<div aria-live="polite">Live region</div>

// Valid values: "off", "polite", "assertive"

8. Conflicting ARIA Attributes

Detects: aria-label and aria-labelledby used together

// ❌ Error: Both attributes present (aria-labelledby takes precedence)
<div aria-label="Label" aria-labelledby="other-id">Content</div>

// ✅ Correct: Use only one
<div aria-labelledby="other-id">Content</div>

9. Redundant Roles

Detects: Explicit roles that match native HTML semantics

// ❌ Error: Redundant role
<button role="button">Click me</button>
<nav role="navigation">Nav</nav>
<a href="#" role="link">Link</a>

// ✅ Correct: Use native semantics
<button>Click me</button>
<nav>Nav</nav>
<a href="#">Link</a>

Supported ARIA Attributes (Dynamic Validation)

The plugin validates these dynamic ARIA state attributes:

  • aria-expanded - Toggle buttons, expandable elements
  • aria-selected - Tabs, selectable options
  • aria-checked - Checkboxes, radio buttons, switches
  • aria-pressed - Toggle buttons
  • aria-hidden - Dynamically shown/hidden elements
  • aria-disabled - Dynamically enabled/disabled elements
  • aria-modal - Dialogs, modals
  • aria-current - Current active item indicators
  • aria-valuenow, aria-valuemin, aria-valuemax - Range widgets (sliders, progress bars)
  • aria-level - Hierarchical level
  • aria-posinset, aria-setsize - Set position and size

Supported Interactive Roles

Elements with these roles are expected to have dynamic ARIA states:

  • button, tab, checkbox, radio, switch
  • menuitem, menuitemcheckbox, menuitemradio
  • option, treeitem, slider, progressbar
  • dialog, alertdialog

Examples

Valid Patterns ✅

// Ternary operator for string conversion
<button aria-expanded={isOpen ? 'true' : 'false'}>Toggle</button>

// String() function
<button aria-pressed={String(isPressed)}>Toggle</button>

// .toString() method
<div aria-hidden={isHidden.toString()}>Content</div>

// Inverted boolean with ternary
<button aria-expanded={!isOpen ? 'true' : 'false'}>Toggle</button>

// Static ARIA on non-interactive element (no handler)
<div aria-label="static label">Content</div>

Invalid Patterns ❌

// Direct boolean binding
<button aria-expanded={isOpen}>Toggle</button>
// Fix: aria-expanded={isOpen ? 'true' : 'false'}

// Logical expression without string conversion
<button aria-expanded={foo && bar}>Toggle</button>
// Fix: aria-expanded={foo && bar ? 'true' : 'false'}

// Static value with event handler
<button onClick={handleClick} aria-expanded="false">Toggle</button>
// Fix: Use dynamic state binding

// Interactive role with static ARIA
<div role="tab" aria-selected="true">Tab</div>
// Fix: Use dynamic state binding

Technical Implementation

Technology Stack

  • Base: ESLint plugin (Node.js environment)
  • Parser: @babel/eslint-parser or TypeScript parser for JSX/TSX AST parsing
  • ARIA Data Source: aria-query role/property definitions for role-attribute compatibility
  • Analysis: Visitor pattern on JSX elements

Analysis Logic

  1. JSXElement Traversal: Identifies role and aria-* attributes
  2. Pattern Analysis: Detects boolean-like bindings and static-value patterns in JSX expressions
  3. State Inference Heuristics: Infers likely state variables from handler/setter patterns (e.g., setX(!x))
  4. Pattern Validation: Checks for proper string conversion patterns

Expected Benefits

1. Accessibility Quality Improvement

Catch dynamic ARIA errors at build/CI phase instead of runtime

2. Developer Productivity

Apply targeted suggestions for repetitive ARIA state binding errors

3. Standardization

Enforce consistent dynamic ARIA usage patterns across projects

Development

Running Tests

npm test

Contributing

Contributions welcome! Please feel free to submit issues or pull requests.

License

MIT

Keywords

  • eslint
  • eslint-plugin
  • accessibility
  • a11y
  • aria
  • jsx
  • react
  • state-validation
  • dynamic-attributes

Related Projects


Note: This plugin focuses on static analysis of ARIA state binding patterns. For comprehensive accessibility testing, combine with runtime testing tools like axe-core.