7.7 KiB
⚡ Click-to-Component
A zero-config, high-precision component inspector and Click-to-Component developer tool for Next.js and React applications.
Hover over any UI element on your web page while holding Alt (or Option) to highlight component boundaries in real time, and click to instantly jump to the exact file, line, and column in your IDE (Antigravity IDE, VS Code, Cursor, WebStorm, Sublime Text, etc.).
✨ Features
- 🎯 Direct IDE Jump: Opens your active IDE and focuses the exact file and cursor position (
file.tsx:line:col). - 🔍 Live Hover Highlighting: Holding Alt outlines the component under your mouse with dynamic bounding box tracking and smooth scroll support.
- 🔀 Dual Hierarchy Modes:
- Outer Component Mode (Alt): Selects the outer component or section container.
- Inner Leaf Mode (Alt + Ctrl / Cmd): Drills down directly to the exact innermost child element (e.g.
<svg>,<button>,<span>). - Live Dynamic Toggle: Press or release Ctrl while hovering to switch between Outer and Inner mode in real time!
- 🏷️ Smart Component Badge: Displays the JSX tag name (e.g.
<section>,<button>), short relative file path, line number, and active inspection mode pill (OUTER/INNER). - 📱 Mobile & Tablet Ready: Floating draggable inspector button with tap-to-inspect on touch devices.
- 🛡️ Zero Production Overhead: Completely disabled, tree-shaken, and stripped out in production builds.
🏗️ Architecture & How It Works
The system operates across three interconnected layers:
flowchart TD
subgraph BuildTime["1. Build-Time AST Transform"]
A[Babel / Compiler] -->|add-data-locator.cjs| B[Injects data-locator attribute on JSX elements]
end
subgraph ClientSide["2. Client Runtime"]
B --> C[DevClickToComponent]
C -->|Alt + Hover| D[Draws Emerald Bounding Box for Outer Component]
C -->|Alt + Ctrl + Hover| E[Draws Cyan Bounding Box for Inner Element]
C -->|Alt + Click| F[Sends locator to API]
end
subgraph ServerSide["3. Local Server API"]
F -->|POST /api/open-in-ide| G[route.ts]
G -->|CLI Command Execution| H[antigravity-ide / code -r -g filepath:line:col]
H --> I[IDE Opens & Focuses Line]
end
📁 Repository Structure
click-to-component/
├── add-data-locator.cjs # Babel AST plugin to inject data-locator attributes
├── .babelrc.example # Babel configuration example
├── client/
│ └── dev-click-to-component.tsx # React Client Component (Inspector UI & Listeners)
├── server/
│ └── route.ts # Next.js App Router API Route (/api/open-in-ide)
├── package.json # Standalone package metadata
└── README.md # Documentation
🚀 Quick Setup & Installation
Step 1: Install Babel Plugin
Copy add-data-locator.cjs to your project root.
Create or update .babelrc in your project root:
{
"presets": ["next/babel"],
"env": {
"development": {
"plugins": [
"./add-data-locator.cjs"
]
}
}
}
Note: Scoping the plugin inside
"env": { "development": ... }guarantees that nodata-locatorattributes will be added to your production builds.
Step 2: Add the Server API Route
Create the file app/api/open-in-ide/route.ts and copy server/route.ts into it:
import { NextResponse } from "next/server";
import { exec } from "child_process";
import os from "os";
export async function POST(req: Request) {
if (process.env.NODE_ENV !== "development") {
return NextResponse.json(
{ message: "Not available in production" },
{ status: 404 }
);
}
try {
const { locator } = await req.json();
if (!locator) {
return NextResponse.json({ message: "Locator is required" }, { status: 400 });
}
const isWindows = os.platform() === "win32";
const bin = isWindows ? "antigravity-ide.cmd" : "antigravity-ide";
const cmd = `${bin} -r -g "${locator}"`;
return new Promise<Response>((resolve) => {
exec(cmd, (error) => {
if (error) {
const fallbackBin = isWindows ? "code.cmd" : "code";
const fallbackCmd = `${fallbackBin} -r -g "${locator}"`;
exec(fallbackCmd, (fallbackError) => {
if (fallbackError) {
resolve(
NextResponse.json(
{ message: "Failed to open file in IDE", error: error.message },
{ status: 500 }
)
);
} else {
resolve(NextResponse.json({ success: true, via: "code" }));
}
});
return;
}
resolve(NextResponse.json({ success: true, via: "antigravity" }));
});
});
} catch (err: unknown) {
const message = err instanceof Error ? err.message : String(err);
return NextResponse.json(
{ message: "Internal server error", error: message },
{ status: 500 }
);
}
}
Step 3: Add the Client Component
Copy client/dev-click-to-component.tsx to app/components/dev-click-to-component.tsx (or components/dev-click-to-component.tsx).
Include it in your root layout (app/layout.tsx):
import { DevClickToComponent } from "./components/dev-click-to-component";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
{process.env.NODE_ENV === "development" && <DevClickToComponent />}
</body>
</html>
);
}
🎮 How to Use
Desktop Shortcuts
| Shortcut | Mode | Highlight Color | Target |
|---|---|---|---|
| Alt + Hover | OUTER |
🟩 Emerald Green (#2dd9a4) |
Outer Component / Section Container |
| Alt + Ctrl + Hover (or Alt+Cmd on Mac) | INNER |
🟦 Electric Cyan (#38bdf8) |
Innermost leaf element under mouse cursor |
| Alt + Click | Open | ⚡ Flash Pulse | Opens the currently highlighted element in your IDE |
Mobile / Touch Devices
- A floating draggable button appears on screens $\le 768\text{px}$.
- Tap the button to toggle Inspect Mode.
- Tap any element on screen to highlight it and open its source code in the IDE.
💻 Supported IDEs & Protocol Fallbacks
When the local CLI is invoked, the system opens your existing active IDE window using -r -g <filepath>:<line>:<col>:
- Antigravity IDE (
antigravity-ide -r -g) - VS Code / VS Code Insiders (
code -r -g) - Cursor (
cursor -r -g)
If the API route is unreachable (e.g. running inside certain sandboxed iframe environments), the client automatically falls back to browser URL protocol schemes:
antigravity://file/<locator>cursor://file/<locator>vscode://file/<locator>webstorm://open?file=<locator>subl://open?url=file://<locator>atom://open?url=file://<locator>
🛡️ Production Safety & Performance
- Compiler Level: In
NODE_ENV === "production",add-data-locator.cjsreturns early without modifying the AST. - Bundle Level: In
app/layout.tsx,{process.env.NODE_ENV === "development" && <DevClickToComponent />}evaluates tofalseduringnext build, allowing bundlers to completely tree-shake the client component out of the production bundle. - Runtime Level: Event listeners and rendering are guarded with
process.env.NODE_ENV !== "development". - Security Level: The
/api/open-in-ideroute returns a404in production environments, preventing arbitrary command execution.
📄 License
MIT