vite-plugin-iris
v0.1.2
Published
Dev-mode element inspector for Vite + React: tags JSX with source locations.
Downloads
330
Maintainers
Readme
Iris
See your UI. Find your code.
Iris is a dev-mode element inspector for Vite. Press one key, click any element in your running app, and see what it is in your codebase — which component, which file and line, which CSS rules, which design tokens — with every fact one click from opening in your editor or handing to your AI.
Browser DevTools understands the DOM; Iris understands your codebase. It answers the question you're actually asking — "what in my code makes it look this way?" — built for designers, front-end developers, and vibe coders whose source of truth is the running app, not the IDE.
Install
Let your AI agent do it
Paste this into Cursor, Claude Code, or any coding agent working in your project:
Install vite-plugin-iris (a dev-only element inspector for Vite) in this project:
1. Run: npm install -D vite-plugin-iris
2. Update my Vite config so Iris loads lazily and ONLY for the dev server —
never during build or in CI. The config must export an async function that
checks `command === 'serve'` and imports the plugin inside a try/catch, so
production builds never even import it. Target shape:
export default defineConfig(async ({ command }) => {
const plugins = [/* my existing plugins, unchanged */];
if (command === 'serve') {
try { plugins.unshift((await import('vite-plugin-iris')).default()); } catch {}
}
return { plugins };
});
Preserve all my existing plugins and options exactly as they are.
3. Verify: start the dev server and confirm the served HTML contains
<script type="module" src="/@iris/overlay"> near </body>.
4. Tell me it's ready and that I toggle it with Option+I (⌥+I) or the
on-page keycap button.Or by hand
npm install -D vite-plugin-irisIn vite.config.js / vite.config.mjs, load Iris lazily and only for the dev server — this keeps it completely out of production builds, deploys, and CI:
import { defineConfig } from 'vite';
export default defineConfig(async ({ command }) => {
const plugins = [/* react(), ... */];
if (command === 'serve') {
try {
const iris = (await import('vite-plugin-iris')).default;
plugins.unshift(iris());
} catch {}
}
return { plugins };
});Run your dev server as usual and press ⌥ + I (or click the keycap in the top-right corner). Deploys are safe by design: the plugin is dev-only (apply: 'serve'), and the lazy import above means your build never even imports Iris.
Default editor (optional). Switchable at runtime in the panel; set the initial default with:
iris({ editor: 'cursor' }) // 'vscode' (default) | 'cursor' | 'antigravity' | 'custom'
iris({ editor: 'custom', editorTemplate: 'myeditor://open?file={root}/{file}&line={line}' })Vite just acts as the dev server — your files and deployment are untouched:
# from the folder containing your index.html
npm init -y
npm install -D vite vite-plugin-irisCreate vite.config.mjs next to your index.html:
import { defineConfig } from 'vite';
export default defineConfig(async ({ command }) => {
const plugins = [];
if (command === 'serve') {
try {
plugins.push((await import('vite-plugin-iris')).default());
} catch {}
}
return { plugins };
});Serve with npx vite and open the printed URL. All .html pages are tagged automatically.
vite.config.mjsmust be in the same folder you runnpx vitefrom (next toindex.html).- Make sure the browser tab is the Vite URL (e.g.
localhost:5173), not an old server or afile://page. - View page source: you should see
<script type="module" src="/@iris/overlay">near</body>. If it's missing, the plugin didn't load — restart the dev server.
What it does
- Element → source — every element knows its component and
file:line, tagged at compile time (JSX and plain HTML) - Context-first breadcrumb —
App page › hero header › hero-title h1, every level clickable to re-target or jump to source - CSS, resolved and honest — every matching rule with its file:line; cascade losers struck through; always the final value, never
var()orinherit. What you authored gets full weight; what the browser computed is muted and labeled for what it is (inherited from <body>,computed by layout) — never a false source - Spacing attributed to its real source — DevTools can't tell you whether that space is your margin or the parent's
gap; Iris can: contextual spacing is labeled (gap · 8px · from parent) and jumps to the parent's rule, and the box model, parent boundary, and flex/grid gaps are drawn on the live page - Tokens view — the element's design tokens grouped by category with color swatches, each with its definition site, cross-file conflict detection, and a usage count showing the blast radius of editing it; hardcoded colors get a nearest-token suggestion with a copy-ready fix
- Handoff — Open in editor at the exact line, and Copy AI context: structured markdown describing the element, its rules, and tokens, ready to paste to your AI for a precise edit
Using it
| Action | How |
|---|---|
| Toggle inspect mode | keycap button (drag it anywhere — it remembers) or ⌥ + I |
| Exit | Esc or toggle again |
| Highlight / lock | hover any element / click it |
| Re-target | click a breadcrumb level |
| Jump to code | click any file:line, class chip, CSS line, or token |
| Explanations | hover a class or CSS line; pin 📌 to keep one open |
| Box model / gaps on the page | expand Spacing and toggle the overlay pills (all / margin / padding / gap) |
| Tokens view | switch views at the top of the panel |
| Panel in the way? | it steps aside from the selected element automatically; drag it to override (position persists) |
| Hand off to AI | Copy AI context, paste into your AI chat |
Principles
- Read-only, always. Iris never writes to your source — you (or your AI, directed by you) make every change.
- Local static analysis only. No network, no AI calls.
- Never in production.
vite buildoutput is byte-for-byte unaffected. - Annotation, not replacement. Real class names and file locations stay visible; plain language sits beside them, not instead of them.
- Quiet by default. Red is reserved for true errors, like a token defined twice with conflicting values.
Roadmap
v1 is deliberately small: the inspect loop done well, plus the element-scoped tokens view. Next, roughly in order:
- Project view — the whole-project token audit: full token library, cross-file conflicts, unused tokens, project-wide hardcoded values, and confirmed one-click token fixes
- Token picker — "what token should I use here" while inspecting
- Annotations + review queue — note elements, send the batch to your AI for a revision round
- MCP context provider — let Cursor / Claude Code query Iris directly instead of copy-paste
- Component library view — auto-generated, zero-config component map with overlap detection
- Tailwind & more frameworks — Next.js/webpack via unplugin, driven by demand
Contributing & development
Issues and bug reports are very welcome; for features, please open an issue to discuss before sending a PR — v1 scope is intentionally tight.
npm install
npm run dev # React demo → localhost:5173
npm run dev:vanilla # vanilla demo → localhost:5173
npm test # vitest unit suitepackages/inspector/ is the plugin; demo/ (React 18) and demo-vanilla/ (no framework) are test beds, each with a deliberate --color-primary conflict for exercising token-conflict detection.
