webcrafts-studio / lens-for-laravel
A plug-and-play accessibility auditor for Laravel.
Package info
github.com/webcrafts-studio/lens-for-laravel
pkg:composer/webcrafts-studio/lens-for-laravel
Requires
- php: ^8.2
- illuminate/routing: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
- laravel/ai: ^0.3.2
- spatie/browsershot: ^4.0|^5.0
Requires (Dev)
- laravel/boost: ^2.2
- laravel/pint: ^1.27
- mockery/mockery: ^1.6
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.0
- pestphp/pest-plugin-laravel: ^3.0
README
A local-first accessibility auditor for Laravel applications.
Lens for Laravel scans your application with axe-core, renders JavaScript through Spatie Browsershot, maps violations back to source files, and can generate AI-assisted fixes for Blade, React, and Vue code.
v2.0.0 focus: Laravel teams using Blade, Livewire, Inertia, React, Vue, or mixed frontends.
Documentation & full feature overview -> lens.webcrafts.pl
Features
- Axe-core scanning - WCAG 2.x and best-practice checks through the industry-standard axe engine.
- JavaScript rendering - scans the hydrated browser DOM through Browsershot/Chromium.
- Blade, React, and Vue source locator - maps DOM violations back to
resources/views/**/*.blade.phpand frontend files underresources/js. - Source type labels - results include
sourceTypevalues:blade,react, orvue. - Inertia-aware file discovery - React/Vue pages under
resources/js/Pages/**are included automatically. - AI Fix assistant - generates reviewable fixes and applies them to Blade, React, and Vue files.
- Diff preview before apply - inspect AI changes before writing to disk.
- Whole-site crawler - discovers pages from sitemaps and internal links.
- SPA crawler mode - optionally renders JavaScript while crawling React/Vue/Inertia apps.
- Multi-URL scans - scan selected URLs in a single dashboard or CLI run.
- Scan history - stores scan runs, issue counts, affected URLs, source locations, and trend data.
- Scan comparison - compare two historical scans to see new, fixed, and remaining issues.
- Element preview - screenshot the page with the failing element highlighted.
- PDF reports - export audit results as a PDF.
- CLI audits - run
php artisan lens:auditwith WCAG filters, crawl mode, and CI thresholds. - IDE links - open source locations in VS Code, Cursor, PhpStorm, or Sublime Text.
- Developer dashboard - zero build step dashboard using Alpine.js and Tailwind CSS via CDN.
Requirements
| Requirement | Version |
|---|---|
| PHP | ^8.2 |
| Laravel | ^10.0 | ^11.0 | ^12.0 | ^13.0 |
| Node.js | Any recent LTS |
| Puppeteer | ^21 recommended |
| Chromium | Provided by Puppeteer or your environment |
Lens uses Browsershot to control Chromium. Install Puppeteer in the host application:
npm install puppeteer --save-dev
If your environment requires a custom Chromium, Node, or npm path, configure Browsershot through your application environment as you normally would.
Installation
Install Lens as a development dependency:
composer require webcrafts-studio/lens-for-laravel --dev
The service provider is auto-discovered.
Run migrations if you want scan history:
php artisan migrate
Publish the config when you want to customize behavior:
php artisan vendor:publish --tag="lens-for-laravel-config"
Optionally publish package views:
php artisan vendor:publish --tag="lens-for-laravel-views"
Quick Start
Start your Laravel app and open:
http://your-app.test/lens-for-laravel/dashboard
Enter a URL from the same host as APP_URL, then run a scan. Results include:
- WCAG level and impact
- failing DOM snippet
- CSS selector
- source file, line number, and source type when located
- Deque/WCAG documentation links
- element preview screenshot
- optional AI fix workflow
Supported Frontends
Blade
Blade support is the most direct path. Lens scans the rendered DOM and searches resources/views/**/*.blade.php for matching elements, IDs, names, classes, and selectors.
AI Fix can modify located .blade.php files under resources/views.
Livewire
Livewire works through the rendered DOM and Blade source locator. For delayed hydration or UI updates, use:
LENS_FOR_LARAVEL_SCAN_WAIT_MS=500
Automated scans only inspect the current browser state after page load. Interactive states such as open modals, validation errors, dropdowns, and tabs still need targeted URLs or manual review.
React
Lens locates React source files under:
resources/js/**/*.js
resources/js/**/*.jsx
resources/js/**/*.ts
resources/js/**/*.tsx
It supports common JSX/TSX patterns such as:
- static attributes:
id="logo",name="email" - JSX expressions:
href={'/pricing'} className- selector variants like
primary-button,primaryButton, andPrimaryButton - Inertia pages under
resources/js/Pages/**
AI Fix can modify supported React files under resources/js.
Vue
Lens locates Vue single-file components under:
resources/js/**/*.vue
It supports common Vue template patterns such as:
- static attributes:
class="logo",href="/pricing" - bindings:
:href="'/pricing'",v-bind:href="'/pricing'" - class object keys:
:class="{ active: isActive }"
AI Fix can modify .vue files under resources/js.
Inertia
Inertia React and Vue apps are supported through the React/Vue source locators. For route discovery in SPA-heavy apps, enable JavaScript crawling:
LENS_FOR_LARAVEL_CRAWLER_RENDER_JAVASCRIPT=true
Dashboard
The dashboard has two primary tabs.
Scanner
Run scans in three modes:
- single URL
- multiple URLs
- whole website crawl
Each issue can be expanded to inspect the failing node, copy the selector, preview the element, open the source file in your editor, or request an AI fix.
History
History stores scan runs and issue metadata in your database. It supports:
- paginated scan history
- trend chart for recent scans
- scan details
- deleting old scans
- comparing two scans to identify new, fixed, and remaining issues
Artisan Command
Run audits from the terminal:
# Audit the app root URL php artisan lens:audit # Audit specific URLs php artisan lens:audit http://your-app.test/about http://your-app.test/contact # Crawl and audit discovered internal pages php artisan lens:audit --crawl # Level A violations only php artisan lens:audit --a # Level A and AA violations php artisan lens:audit --aa # All levels, including AAA and best-practice php artisan lens:audit --all # Fail with exit code 1 when violations exceed a threshold php artisan lens:audit --threshold=10
The CLI uses the same scanner, crawler, source locator, and source type metadata as the dashboard.
Configuration
Published config file:
return [ 'route_prefix' => 'lens-for-laravel', 'middleware' => ['web'], 'enabled_environments' => [ 'local', ], 'editor' => env('LENS_FOR_LARAVEL_EDITOR', 'vscode'), 'crawl_max_pages' => env('LENS_FOR_LARAVEL_CRAWL_MAX_PAGES', 50), 'crawler_render_javascript' => env('LENS_FOR_LARAVEL_CRAWLER_RENDER_JAVASCRIPT', false), 'scan_wait_ms' => env('LENS_FOR_LARAVEL_SCAN_WAIT_MS', 0), 'ai_provider' => env('LENS_FOR_LARAVEL_AI_PROVIDER', 'gemini'), ];
Environment Options
LENS_FOR_LARAVEL_EDITOR=vscode LENS_FOR_LARAVEL_CRAWL_MAX_PAGES=50 LENS_FOR_LARAVEL_CRAWLER_RENDER_JAVASCRIPT=false LENS_FOR_LARAVEL_SCAN_WAIT_MS=0 LENS_FOR_LARAVEL_AI_PROVIDER=gemini
Supported editors:
vscodecursorphpstormsublimenone
Supported AI providers:
geminiopenaianthropic
Crawling
Whole-site scans discover URLs in this order:
sitemap.xmlsitemap_index.xmlsitemaps/sitemap.xml- internal
<a href>links
By default, crawling uses Laravel's HTTP client and parses the initial HTML. This is fast and works well for Blade, Livewire, and server-rendered pages.
For SPA or Inertia apps where links are rendered after JavaScript hydration:
LENS_FOR_LARAVEL_CRAWLER_RENDER_JAVASCRIPT=true
With that enabled, Lens attempts to render each crawled page in Chromium and collect links from the hydrated DOM. If browser crawling fails or finds no links, it falls back to the HTTP crawler.
Limit the crawl size with:
LENS_FOR_LARAVEL_CRAWL_MAX_PAGES=100
AI Fix
The AI Fix workflow:
- Lens locates the source file and line.
- It reads a context window around the issue.
- It sends the issue, failing DOM snippet, WCAG tags, and source context to the configured AI provider.
- It returns an explanation and full replacement code block.
- The dashboard shows a diff preview.
- You can accept and apply the change.
Configure provider credentials:
LENS_FOR_LARAVEL_AI_PROVIDER=gemini GEMINI_API_KEY=your-key-here # or LENS_FOR_LARAVEL_AI_PROVIDER=openai OPENAI_API_KEY=your-key-here # or LENS_FOR_LARAVEL_AI_PROVIDER=anthropic ANTHROPIC_API_KEY=your-key-here
Supported writable files:
resources/views/**/*.blade.phpresources/js/**/*.jsresources/js/**/*.jsxresources/js/**/*.tsresources/js/**/*.tsxresources/js/**/*.vue
AI Fix does not write outside those paths.
IDE Integration
When a source location is found, click it in the dashboard to open your editor at the exact line.
LENS_FOR_LARAVEL_EDITOR=vscode
Use none to disable editor links:
LENS_FOR_LARAVEL_EDITOR=none
Scan Output
Each issue includes fields like:
{
"id": "image-alt",
"impact": "critical",
"description": "Images must have alternate text",
"helpUrl": "https://dequeuniversity.com/rules/axe/...",
"htmlSnippet": "<img class=\"logo\" src=\"/logo.png\">",
"selector": ".logo",
"tags": ["wcag2a"],
"url": "http://your-app.test",
"fileName": "js/Components/Logo.vue",
"lineNumber": 12,
"sourceType": "vue"
}
sourceType can be:
bladereactvuenullwhen no source location is found
Security
Lens is intended for local and controlled development environments.
Built-in protections:
- Dashboard access is restricted by
enabled_environments. - Scan URLs must use HTTP or HTTPS.
- Scan URLs must match the host configured in
APP_URL. - External domain scanning is blocked.
- AI Fix apply rejects path traversal.
- AI Fix writes only to supported Blade/React/Vue source paths.
- AI Fix blocks generated code containing server-side execution functions such as
shell_exec,system,exec,passthru,proc_open,popen, andeval. - AI Fix blocks newly introduced raw PHP open tags unless they were already present in the original code block.
- Fix writes use
LOCK_EX. - Scan, crawl, preview, fix, history, and report endpoints use throttling where appropriate.
Recommended production posture:
'enabled_environments' => ['local'],
If you enable Lens on staging, protect the route with authentication middleware:
'middleware' => ['web', 'auth'],
Known Limitations
Automated accessibility testing cannot prove full compliance. Axe-core usually detects only a portion of WCAG issues.
Source location is heuristic. Lens can locate many common Blade, React, Vue, and Inertia patterns, but it may miss or misidentify:
- deeply abstracted components
- custom components that render HTML internally, such as
<LogoImage /> - dynamic class builders with no literal class or recognizable variant
- CSS module keys that do not resemble the final generated class
- runtime-generated attributes
- elements rendered only after user interaction
For interactive states, run targeted scans after exposing the state, add dedicated URLs, or combine Lens with manual QA.
Always complement Lens with:
- keyboard navigation testing
- screen reader testing with NVDA, JAWS, or VoiceOver
- manual form validation checks
- modal, menu, dropdown, accordion, and tab interaction checks
- cognitive and usability review
Upgrade Notes for v2.0.0
Version 2 adds major frontend support and persistence features:
- React source locating and AI Fix
- Vue source locating and AI Fix
- Inertia-friendly source discovery
sourceTypemetadata- scan history tables
- scan comparison
- SPA crawler option
- scan wait option
After upgrading:
php artisan migrate
php artisan vendor:publish --tag="lens-for-laravel-config"
If you already published the config, manually add:
'crawler_render_javascript' => env('LENS_FOR_LARAVEL_CRAWLER_RENDER_JAVASCRIPT', false), 'scan_wait_ms' => env('LENS_FOR_LARAVEL_SCAN_WAIT_MS', 0),
Testing This Package
vendor/bin/pint --dirty vendor/bin/pest
License
The MIT License (MIT). See LICENSE.md for details.