Accessibility Inspector

Runs axe-core against the user app, lists WCAG A/AA violations in a Solid panel, and highlights the element on hover.

Runs axe-core against the user app, lists WCAG A/AA violations in a Solid panel, and highlights the element on hover.

Package: @devframes/plugin-a11y · framework: Solid + Vite

Hover to highlight the offending element

Generate prompts to fix issues

What it does

Three pieces, two browser-side:

PieceRuns inRole
Page scriptthe user app's pageruns axe-core, owns the report state, draws the highlight ring
Panelthe devtools iframeSolid SPA: lists violations, highlights on hover
Node sidethe Node processthe get-config RPC (impact taxonomy), baked in static builds

The page script and the panel talk over the in-page channel, so the loop works live or static. The page script is the author-provided bridge (the panel has no reach into the user app's DOM) — one module script scans, reports, and highlights.

In a hub

The definition declares the page script as its dock client script, so mounting by package name just works:

initHub({ devframes: ['@devframes/plugin-a11y'] })

The hub serves the bundle same-origin and a client runtime imports it into the host page. Each scan also mirrors into the hub's messages feed — a summary plus one per rule.

A host can also mount the module itself — e.g. a Vite host via /@fs/:

import createA11yDevframe, { a11yPageScriptBundlePath } from '@devframes/plugin-a11y'

await ctx.install(createA11yDevframe(), {
  dock: { clientScript: { importFrom: `/@fs/${a11yPageScriptBundlePath}` } },
})

Outside a hub, a <script type="module"> boots the page script (no feed mirror).

Standalone

pnpx @devframes/plugin-a11y

Runs the panel alone at /__devframes_plugin_a11y/; load the page script into a real page.

Mount into a Vite host

In Vite DevTools:

// vite.config.ts
import createA11yDevframe from '@devframes/plugin-a11y'
import { createPluginFromDevframe } from '@vitejs/devtools-kit/node'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    createPluginFromDevframe(createA11yDevframe()),
  ],
})

Or swap in devframeVite(createA11yDevframe()) from @devframes/vite/single.

Programmatic

createA11yDevframe(options) returns a definition for any adapter:

import { createA11yDevframe } from '@devframes/plugin-a11y'

export default createA11yDevframe({
  port: 9899,
})

RPC

Namespaced devframes:plugin:a11y:*:

FunctionTypeReturns
get-configstaticThe impact taxonomy and the in-page channel coordinates.

Run the demo

The demo serves a broken page and panel from one origin:

pnpm -C plugins/a11y build       # build the panel + the page-script bundle
pnpm -C plugins/a11y demo        # dev: live WebSocket RPC
pnpm -C plugins/a11y cli:build   # bake the static deploy (dist/static)
pnpm -C plugins/a11y demo:build  # static: baked RPC dump, no server

Hover a row to highlight the matching element.

Source

plugins/a11y