Bumi Accessibility Language Server Protocol server for IDE integration
npm install @flatelectronics/accessibility-lsp-serverA Language Server Protocol (LSP) server for accessibility linting that can be used with any LSP-compatible editor, including JetBrains IDEs (IntelliJ IDEA, WebStorm, PHPStorm, etc.).
Developer: Flat Electronics Canada Limited
License: MIT
GitHub: https://github.com/bumi-ca/accessibility-scanner-core
- 19 accessibility rules covering WCAG 2.0, 2.1, and 2.2
- Support for HTML, JSX/TSX, Vue, Angular, and Razor files
- Real-time diagnostics as you type
- Quick fixes for common accessibility issues
- ARIA completions for roles and attributes
- Configurable WCAG conformance level (A, AA, AAA)
``bash`
npm install -g @flatelectronics/accessibility-lsp-server
`bash`
cd lsp-server
npm install
npm run build
The server communicates via stdin/stdout:
`bash`
bumi-lspor
node dist/server.js
JetBrains IDEs require the LSP4IJ plugin to connect to LSP servers.
#### Step 1: Install LSP4IJ Plugin
1. Open your JetBrains IDE (IntelliJ IDEA, WebStorm, etc.)
2. Go to Settings/Preferences > Plugins
3. Click Marketplace tab
4. Search for "LSP4IJ"
5. Click Install and restart the IDE
#### Step 2: Configure Bumi LSP Server
1. Go to Settings/Preferences > Languages & Frameworks > Language Servers
2. Click the + button to add a new server
3. Configure the server:
- Name: Bumi Accessibilitybumi-lsp
- Command: (if installed globally) or the full path to node /path/to/lsp-server/dist/server.js.html;.htm;.jsx;.tsx;.vue;.cshtml;*.razor
- File patterns:
4. Click OK to save
#### Step 3: Verify Installation
1. Open an HTML or JSX file
2. Add an tag without an alt attribute
3. You should see a diagnostic warning from Bumi
Using nvim-lspconfig:
`lua
local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')
if not configs.bumi then
configs.bumi = {
default_config = {
cmd = { 'bumi-lsp' },
filetypes = { 'html', 'javascriptreact', 'typescriptreact', 'vue' },
root_dir = lspconfig.util.root_pattern('package.json', '.git'),
settings = {
bumi = {
enabled = true,
wcag = {
version = '2.2',
level = 'AA'
}
}
}
}
}
end
lspconfig.bumi.setup{}
`
Using LSP package:
`json`
{
"clients": {
"bumi": {
"command": ["bumi-lsp"],
"enabled": true,
"selector": "source.html, source.jsx, source.tsx, text.html.vue",
"settings": {
"bumi": {
"enabled": true,
"wcag": {
"version": "2.2",
"level": "AA"
}
}
}
}
}
}
Using lsp-mode:
`elisp
(require 'lsp-mode)
(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection '("bumi-lsp"))
:activation-fn (lsp-activate-on "html" "javascriptreact" "typescriptreact" "vue")
:server-id 'bumi))
(add-hook 'html-mode-hook #'lsp)
(add-hook 'web-mode-hook #'lsp)
`
The server accepts configuration via the bumi namespace:
`json`
{
"bumi": {
"enabled": true,
"wcag": {
"version": "2.2",
"level": "AA"
},
"rules": {
"disabled": []
}
}
}
| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| bumi.enabled | boolean | true | Enable/disable the linter |bumi.wcag.version
| | string | "2.2" | WCAG version: "2.0", "2.1", or "2.2" |bumi.wcag.level
| | string | "AA" | Conformance level: "A", "AA", or "AAA" |bumi.rules.disabled
| | array | [] | List of rule IDs to disable |
The server includes 19 accessibility rules:
| Rule ID | WCAG | Level | Version | Description |
|---------|------|-------|---------|-------------|
| IMG_MISSING_ALT | 1.1.1 | A | 2.0 | Image missing alt attribute |
| IMG_SUSPICIOUS_ALT | 1.1.1 | A | 2.0 | Suspicious alt text patterns |
| BUTTON_NO_NAME | 4.1.2 | A | 2.0 | Button without accessible name |
| LINK_EMPTY | 2.4.4 | A | 2.0 | Empty link element |
| LINK_GENERIC_TEXT | 2.4.4 | A | 2.0 | Generic link text |
| INPUT_MISSING_LABEL | 1.3.1, 3.3.2 | A | 2.0 | Form input missing label |
| HEADING_EMPTY | 1.3.1, 2.4.6 | A | 2.0 | Empty heading element |
| HEADING_SKIP_LEVEL | 1.3.1 | A | 2.0 | Skipped heading level |
| HTML_MISSING_LANG | 3.1.1 | A | 2.0 | Missing lang attribute |
| ARIA_INVALID_ROLE | 4.1.2 | A | 2.0 | Invalid ARIA role |
| ARIA_HIDDEN_FOCUSABLE | 4.1.2 | A | 2.0 | Focusable element with aria-hidden |
| TABINDEX_POSITIVE | 2.4.3 | A | 2.0 | Positive tabindex value |
| AUTOCOMPLETE_MISSING | 1.3.5 | AA | 2.1 | Missing autocomplete attribute |
| FORM_NO_SUBMIT | 2.1.1 | A | 2.0 | Form without submit button |
| TABLE_MISSING_HEADERS | 1.3.1 | A | 2.0 | Table missing headers |
| IFRAME_MISSING_TITLE | 2.4.1, 4.1.2 | A | 2.0 | Iframe missing title |
| VIDEO_MISSING_CAPTIONS | 1.2.2 | A | 2.0 | Video without captions track |
| AUDIO_MISSING_CONTROLS | 1.4.2 | A | 2.0 | Audio without controls |
| TARGET_SIZE_MINIMUM | 2.5.8 | AA | 2.2 | Target size may be too small |
The server provides automatic quick fixes for:
- Adding alt="" to imagesaria-label
- Adding to empty buttonstabindex
- Changing positive to tabindex="0"title
- Adding to iframescontrols
- Adding to audio elements
The server provides completions for:
- ARIA roles (role="button", role="navigation", etc.)aria-label
- ARIA attributes (, aria-labelledby, etc.)alt
- Common accessibility attributes (, tabindex, etc.)
1. Ensure Node.js 18+ is installed
2. Check the server path is correct
3. Verify the server is executable: chmod +x dist/server.js`
1. Check the file type is supported
2. Verify LSP4IJ plugin is installed (JetBrains)
3. Check server logs for errors
1. Ensure LSP4IJ plugin is updated to latest version
2. Restart the IDE after configuration changes
3. Check Help > Show Log in Finder/Explorer for errors
Contributions are welcome! Please see our GitHub repository for guidelines.
MIT License - Copyright (c) 2026 Flat Electronics Canada Limited