oxlint-plugin-vue-sfc-a11y

Vue SFC accessibility rules for oxlint, as a JS plugin. Ports of eslint-plugin-vuejs-accessibility rules, with options upstream does not expose.
6,833
Install
npm install oxlint-plugin-vue-sfc-a11y
Latest Version:0.2.0
License:MIT
Last Updated:Sep 3, 2026
Links: GitHub  ·  npm
Maintainer: togetic

oxlint-plugin-vue-sfc-a11y

Vue SFC accessibility rules for oxlint, as a JS plugin.

oxlint cannot read Vue templates natively (oxc#15761), so projects keep ESLint around for eslint-plugin-vuejs-accessibility. These rules self-parse the SFC with @vue/compiler-sfc and walk the real template AST, so the checks run under oxlint instead.

Role and element semantics come from aria-query — the same data source upstream uses — so the interactive-role and interactive-element sets are identical rather than re-derived.

Companion to oxlint-plugin-vue-sfc, which ports the eslint-plugin-vue template rules.

Install

npm i -D oxlint-plugin-vue-sfc-a11y
{
    "extends": ["./node_modules/oxlint-plugin-vue-sfc-a11y/configs/recommended.json"]
}

The npm package is oxlint-plugin-vue-sfc-a11y (npm rejects oxlint-plugin-vue-a11y as too similar to eslint-plugin-vue-a11y); the plugin namespace is the shorter vue-a11y, so rule ids read vue-a11y/alt-text. All four rules default to warn.

Rules

Rule Default Description
vue-a11y/alt-text warn require a text alternative on img, object, area, input[type="image"]
vue-a11y/aria-props warn disallow aria-* attributes that are not in the ARIA spec
vue-a11y/no-static-element-interactions warn disallow interactive handlers on elements with no keyboard path
vue-a11y/tabindex-no-positive warn disallow positive tabindex

Each is a port of the vuejs-accessibility/* rule of the same name, and defaults to upstream behaviour exactly. Verified against a 1581-SFC production Nuxt codebase: every finding ESLint reports, this reports, at identical line:column.

no-static-element-interactions has options; upstream has none

Upstream declares schema: []. It fires on several shapes that are correct as written, and with no options the only lever left is a project-wide warning ceiling — which suppresses genuine findings just as readily as false ones.

"vue-a11y/no-static-element-interactions": ["warn", {
    "allowDynamicRole": true,
    "allowSharedHandlerChild": true,
    "ignoreElements": ["canvas"],
    "ignoreHandlers": ["mousemove"]
}]
Option Default What it exempts
allowDynamicRole false :role="cond ? 'button' : undefined" — a bound role upstream cannot read, so it treats it as absent
allowSharedHandlerChild false a wrapper whose @click expression is also run from a keyboard handler on a descendant — the real control inside
ignoreElements [] tag names to skip outright
ignoreHandlers [] handler names that should not count as interactive (mousemove is a pointer gesture, not an action)

Why allowSharedHandlerChild and not "has a focusable child"

The obvious version of that option — skip when the subtree contains anything focusable — is wrong, and measurably so. On the codebase this was built against it silenced a real finding: a card whose @click emitted expand, wrapping an unrelated text input. The input is tabbable, so the weak test passed it; expand still had no keyboard path at all.

The question worth asking is not "is something in here focusable" but "can this action be reached from the keyboard". So the option looks for a descendant running the same handler expression from a keydown/keypress/keyup handler. That clears the genuine proxying wrapper (<div @click="switchValue"> around <input @keydown.enter="switchValue">) and leaves the card reported. There is a regression test for both.

Known limitation: diagnostic positions

Template diagnostics render on the <script> block, with the true position prepended to the message:

Comp.vue:31:1  warning  vue-a11y(no-static-element-interactions): [template 12:5] <div> has an interactive handler...

oxlint gives JS-plugin rules a script-relative view of an SFC, so a template position — negative in a template-first file — cannot be expressed. oxc#26001 fixes this upstream with an actualRange, and would give every rule here correct positions with no rule changes.

Tests

npm test    # node:test, 54 specs across 4 rules

License

MIT

Related Packages

oxlint-plugin-vue-sfc

Vue SFC template rules for oxlint, as a JS plugin. Ports of eslint-plugin-vue ru...

6,895 0
oxlint-vue

Vue SFC linting and formatting on the oxc toolchain. Rules reach inside , no esl...

1,592 4
nuxt-a11y

This module integrates Axe tool for auditing website against common Accessibilit...

462
@lexical/a11y

Framework-agnostic accessibility helpers (ARIA live regions, focus management, r...

12,617,619 23,971
@focusring/wcagify

WCAG accessibility audit tool — Nuxt layer with report generation, PDF export an...

5,246 1

Version History

Version Released License
0.2.0 MIT
0.1.2 MIT
0.1.1 MIT
0.1.0 MIT