click-to-source
v1.1.0
Published
Hold a configurable hotkey and click any UI element in development to open, inspect, copy, or link to its source
Downloads
91
Maintainers
Readme
click-to-source
Hold your configured hotkey to preview an element, then click to run the configured source action.
Works by injecting a data-click-to-source attribute at build time, then using a runtime hover/click handler to preview and act on the file at the right line and column.
This package is intentionally a local-development tool. Standard UAT and production builds should not ship data-click-to-source metadata.
Validation Status
Currently validated in automated tests:
- Vite React dev/build flow, including exact source line assertions across JSX, TSX, fragments, render props, wrapped components, loops, conditionals, and a real MUI fixture
- Vite Vue dev/build flow
- Vite Svelte dev/build flow
- Webpack React dev/build flow, including a TypeScript/Babel line-accuracy fixture outside the Vite React Refresh path
- Rspack React dev/build flow
- Angular dev-server template injection for external HTML templates, plus an explicit inline-template regression case
- CLI setup for React, Vue, Svelte, Angular, Webpack, and Rspack project shapes, including framework-specific manual fallback guidance when automatic patching is unsafe
- Runtime hotkey preview highlighting with an animated dashed border, tooltip rendering, open/copy/inspect action modes, selector filters, and delayed initialization when instrumented DOM appears after boot
- Open-file endpoint security, path mappings, Windows editor launching, and launch-candidate coverage for VS Code, Cursor, and WebStorm
- pnpm workspace, Turbo monorepo, and Nx monorepo flows with
allowOutsideWorkspace: true - Next.js webpack-backed dev/build flow, covering both App Router and Pages Router with the checked-in
next-initbootstrap and a local API route for the open endpoint - Nuxt 4 dev/build flow for Vue SFC templates, with browser-side editor URL fallback for local editor opening
- Astro 5 dev/build flow for React islands
- Storybook React/Vite dev/build flow
Manually validated across the checked-in examples:
- React example
- Vue example
- Svelte example
- Angular example
- Webpack React example
- Rspack React example
Implemented, but not yet validated end-to-end in CI:
- Real installed-editor behavior for Cursor and WebStorm on a supported machine
- Path translation in actual WSL, devcontainer, and Codespaces environments
- Angular inline template instrumentation
- Next.js Turbopack dev mode
- Astro support for Vue or Svelte islands
- Raw
.astrotemplate markup instrumentation - Storybook webpack builder beyond config-level coverage
Integrations
- Vite React with
react()plusclickToSourceReact() - Vite Vue
- Vite Svelte
- Webpack and Rspack integrations, validated today with React/Babel loader pipelines
- Angular dev-server integration
- Next.js webpack-mode integration for App Router and Pages Router
- Nuxt module integration
- Astro React-island integration
- Storybook React/Vite integration
- VS Code, Cursor, and WebStorm launch targets
Install
npm install -D click-to-sourceQuick Start
npx click-to-source setupThis will:
- Add
import "click-to-source/init";to your entry file. - Patch
vite.config.*,webpack.config.*,rspack.config.*, orangular.jsonwhen detected.
If it cannot safely patch your config, it prints manual steps.
Then start your dev server, hold the configured hotkey to preview a rendered element, and click to open, copy, or inspect it.
Expected behavior:
- The DOM includes
data-click-to-source="path:line:column"on elements. - Holding the configured hotkey previews the hovered element with a visible outline.
- A tooltip shows the resolved file and line while the hotkey is held.
- Clicking while the configured hotkey is held uses the current action: open, copy source, or inspect.
Manual Setup
If npx click-to-source setup cannot safely patch your project, use one of these minimal shapes.
These are the known-good setups reflected by the checked-in example apps and smoke tests.
Vite React
Known-good example: examples/react-example
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { clickToSourceReact } from "click-to-source/vite";
export default defineConfig({
plugins: [react(), clickToSourceReact()],
});// src/main.tsx
import "click-to-source/init";Vite Vue
Known-good example: examples/vue-example
// vite.config.ts
import { defineConfig } from "vite";
import { clickToSourceVue } from "click-to-source/vite";
export default defineConfig({
plugins: [clickToSourceVue()],
});// src/main.ts
import "click-to-source/init";Vite Svelte
Known-good example: examples/svelte-example
// vite.config.ts
import { defineConfig } from "vite";
import { clickToSourceSvelte } from "click-to-source/vite";
export default defineConfig({
plugins: [clickToSourceSvelte()],
});// src/main.ts
import "click-to-source/init";Webpack React (Babel)
Known-good example: examples/webpack-react-example
// webpack.config.cjs
const { withClickToSource } = require("click-to-source/webpack");
module.exports = (_env, argv = {}) =>
withClickToSource({
mode: argv.mode || "development",
// your existing webpack config
});// src/index.tsx or src/index.jsx
import "click-to-source/init";Rspack React (Babel)
Known-good example: examples/rspack-react-example
// rspack.config.cjs
const { withClickToSource } = require("click-to-source/rspack");
module.exports = (_env, argv = {}) =>
withClickToSource({
mode: argv.mode || "development",
// your existing rspack config
});// src/index.tsx or src/index.jsx
import "click-to-source/init";Angular
Known-good example: examples/angular-example
// angular.json
{
"projects": {
"your-app": {
"architect": {
"serve": {
"builder": "click-to-source:dev-server"
}
}
}
}
}// src/main.ts
import "click-to-source/init";For Angular, the validated path today is external HTML templates in dev mode. Inline templates are still explicitly unsupported.
Next.js
Known-good example: examples/next-example
// next.config.mjs
import withClickToSourceNext from "click-to-source/next";
export default withClickToSourceNext({
reactStrictMode: true,
});// app/click-to-source-client.tsx
"use client";
import "click-to-source/next-init";
export default function ClickToSourceClient() {
return null;
}// pages/api/__click_to_source/open.ts
import { createOpenRequestHandler } from "click-to-source/server";
const handler = createOpenRequestHandler({
path: "/api/__click_to_source/open",
});
export default handler;Notes:
- The validated path today is standard
next dev, notnext dev --turbo. - The runtime helper for Next is
click-to-source/next-init, not the genericinitentry. - The checked-in example covers both App Router and Pages Router.
Nuxt
Known-good example: examples/nuxt-example
// nuxt.config.ts
import { defineNuxtConfig } from "nuxt/config";
import clickToSourceNuxt from "click-to-source/nuxt";
export default defineNuxtConfig({
modules: [clickToSourceNuxt()],
});Notes:
- The validated path today is Nuxt 4 with Vue SFC templates.
- Open action currently relies on the editor URL-scheme fallback in the browser rather than a dedicated local endpoint.
Astro
Known-good example: examples/astro-example
// astro.config.mjs
import { defineConfig } from "astro/config";
import react from "@astrojs/react";
import clickToSourceAstro from "click-to-source/astro";
export default defineConfig({
integrations: [react(), clickToSourceAstro({ framework: "react" })],
});Notes:
- The validated path today is React islands.
- Raw
.astrotemplate markup is still not instrumented.
Storybook
Known-good example: examples/storybook-react-example
// .storybook/main.ts
import { withClickToSourceStorybook } from "click-to-source/storybook";
export default withClickToSourceStorybook(
{
framework: "@storybook/react-vite",
stories: ["../src/**/*.stories.@(ts|tsx)"],
},
{ framework: "react" }
);Notes:
- The validated path today is
@storybook/react-vite. withClickToSourceStorybook()injects the runtime preview entry automatically.- Webpack-builder Storybook support exists at the config-wrapper level, but it is not smoke-validated yet.
Vite
React
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { clickToSourceReact } from "click-to-source/vite";
export default defineConfig({
plugins: [
react(),
clickToSourceReact({
// Optional: allow opening files outside project root (monorepos).
allowOutsideWorkspace: false,
// Optional: allow requests from non-localhost clients.
allowRemote: false,
}),
],
});clickToSourceReact() is additive for Vite React. Keep your normal react() plugin.
// main.tsx
import "click-to-source/init";The React, Vue, and Svelte paths below are all validated in automated smoke tests.
Vue
// vite.config.ts
import { defineConfig } from "vite";
import { clickToSourceVue } from "click-to-source/vite";
export default defineConfig({
plugins: [clickToSourceVue()],
});// main.ts
import "click-to-source/init";Svelte
// vite.config.ts
import { defineConfig } from "vite";
import { clickToSourceSvelte } from "click-to-source/vite";
export default defineConfig({
plugins: [clickToSourceSvelte()],
});// main.ts
import "click-to-source/init";Webpack
The validated manual path today is React with babel-loader.
vue-loader and svelte-loader hooks exist in the wrapper, but they are not yet covered by the checked-in smoke suite.
React (Babel)
// webpack.config.cjs
const { withClickToSource } = require("click-to-source/webpack");
module.exports = (_env, argv = {}) =>
withClickToSource({
mode: argv.mode || "development",
// your existing config with babel-loader
});// entry file
import "click-to-source/init";If your React pipeline already uses babel-loader, withClickToSource() adds the Babel plugin for development automatically.
Rspack
The validated manual path today is React with babel-loader.
// rspack.config.js
const { withClickToSource } = require("click-to-source/rspack");
module.exports = withClickToSource({
// your existing config
});Angular (dev server)
This uses a custom dev-server builder to inject data-click-to-source into templates.
// angular.json (serve builder)
{
"projects": {
"your-app": {
"architect": {
"serve": {
"builder": "click-to-source:dev-server",
"options": {
"clickToSource": {
"enabled": true
}
}
}
}
}
}
}// src/main.ts
import "click-to-source/init";Notes:
- External HTML templates are supported. Inline templates may not include
data-click-to-source. - This is dev-only. Production builds are unaffected.
Examples
Checked-in example apps live in:
examples/react-exampleexamples/vue-exampleexamples/svelte-exampleexamples/angular-exampleexamples/webpack-react-exampleexamples/rspack-react-exampleexamples/next-exampleexamples/nuxt-exampleexamples/astro-exampleexamples/storybook-react-example
Each example is intended to build locally and reflect the currently supported setup shape. React, Vue, Svelte, Angular, Webpack, and Rspack were manually validated locally. Next.js, Nuxt, Astro, and Storybook are covered by the automated adoption smoke suite and still worth a manual pass before release.
Configuration
import { configManager } from "click-to-source";
configManager.updateConfig({
hotkey: "alt",
position: "tr",
theme: "dark",
enabled: true,
});Config options:
interface ClickToSourceConfig {
enabled: boolean;
hotkey: "ctrl" | "alt" | "meta" | "shift";
position: "tl" | "tr" | "bl" | "br";
theme: "light" | "dark" | "auto";
showButton: boolean;
serverPath: string;
serverBaseUrl?: string;
openIn: "vscode" | "cursor" | "webstorm";
pathMappings: Array<{ from: string; to: string }>;
action: "open" | "copy" | "inspect";
includeSelectors: string[];
excludeSelectors: string[];
}pathMappings affect browser fallback, copy mode, and tooltip display. Server-side path mapping is configured on the build-tool integration itself.
Action Modes
The floating UI supports three actions:
open: open the editor at the resolved file, line, and columncopy: copy the resolvedfile:line:columninspect: show the resolved source without opening anything
click-to-source is a localhost/dev-server tool. It does not try to support standard UAT or production deployments by embedding repository links into shipped builds.
If you want shared source links on UAT or production later, that needs a separate product mode with explicit dev-safe metadata rules. The current package does not claim that.
Server Security Defaults
The open-file endpoint is locked down by default:
- Only
GETis accepted. - Only loopback requests (
127.0.0.1/::1) are accepted. - Cross-origin browser requests are blocked.
- Paths outside
process.cwd()are blocked.
For monorepos or remote-device workflows, you can opt in:
clickToSourceReact({
allowOutsideWorkspace: true,
allowRemote: true,
pathMappings: [
{ from: "/workspaces/my-app", to: "C:/Users/mateu/dev/my-app" },
],
});Angular builder options:
{
"clickToSource": {
"enabled": true,
"allowOutsideWorkspace": false,
"allowRemote": false
}
}How It Works
- Build time: A framework-specific transform injects
data-click-to-source="path:line:column"into element tags. - Runtime: Holding the configured hotkey previews the hovered instrumented element, shows a tooltip with the resolved source location, and clicking runs the current action for that location.
- Dev server: A lightweight endpoint triggers
code --goto(or other editors).
Troubleshooting
If clicking does nothing:
- Confirm the build transform is enabled (Vite plugin or Babel plugin).
- Ensure
import "click-to-source/init";is in your entry file. - Check that your editor command is available on PATH (e.g.,
code --version). - If source files are outside your app root, set
allowOutsideWorkspace: truein plugin options. - If you are testing the dev endpoint manually, include the editor in the query string, for example:
/__click_to_source/open?file=src/App.tsx&line=10&column=3&editor=vscodeDevelopment
npm run verify
npm run test:smokenpm run test runs through tsx so the TypeScript tests are executed without Node's experimental strip-types mode.
npm run test:smoke validates packed-install flows for temporary Vite React, Vite React TSX, Vite React with MUI, Vue, Svelte, Angular, Webpack, Webpack TSX, Rspack, Next.js, Nuxt, Astro, Storybook, pnpm workspace, Turbo monorepo, and Nx monorepo apps.
The package is live on npm as click-to-source.
Repository docs:
CHANGELOG.md: released changesRELEASING.md: maintainer release processTODO.md: validation gaps and roadmap
License
MIT
