svelte-trace Svelte Themes

Svelte Trace

A Svelte 5 preprocessor that identifies rendered element's source code location in real-time for devs to debug ✨

Svelte Trace Logo

Svelte Trace

Trace your Svelte components in the DOM—effortlessly.
A Svelte 5 preprocessor that injects data attributes into DOM elements for reliable tooling and debugging.

NPM Version License

Table of Contents

  1. Why Svelte Trace?
  2. Features
  3. Installation
  4. Setup
  5. How It Works
  6. Decoding Trace Metadata
  7. Optional Features
  8. Iframe Message Protocol
  9. Runtime Flags & Teardown
  10. Use Cases
  11. Contributing
  12. Support
  13. License

1. Why Svelte Trace?

When building devtools, visual editors, or automation around Svelte, you constantly need to answer: which part of the source does this DOM node belong to?

Svelte Trace is a preprocessor that answers that automatically. It tags every element in the compiled markup so tools can read its file path, line, and column—plus a stable short ID—directly from the DOM, without maintaining fragile mappings by hand.

2. Features

  • Source location — Elements receive data-svelte-trace encoding file, line, column, and offset metadata.
  • Stable identity — Elements receive data-svelte-trace-id so they can be re-selected after re-renders or HMR.
  • Minimal setup — Configure once in svelte.config.js; no extra wiring needed for the core tagging.
  • Open in editor — Ctrl+Click any element to open its source in VS Code or Cursor.
  • Iframe support — Designed for embedded previews: hover/click events, trace-ready notifications, and programmatic element-click commands are all supported.

3. Installation

npm install svelte-trace --save-dev

4. Setup

4.1 Add to svelte.config.js

Import and add svelteTrace to your preprocessors array:

import adapter from "@sveltejs/adapter-auto";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
import { svelteTrace } from "svelte-trace";

const config = {
    preprocess: [vitePreprocess(), svelteTrace()],
    kit: { adapter: adapter() },
};

export default config;

4.2 Configuration Options

All options are optional. Defaults: openInEditor: "", showIndicator: true, postToParent: true.

// Use defaults
svelteTrace();

// Open source in VS Code on Ctrl+Click
svelteTrace({ openInEditor: "vscode" });

// Open in Cursor, hide overlays, keep postMessage
svelteTrace({ openInEditor: "cursor", showIndicator: false, postToParent: true });
Option Type Default Description
openInEditor "vscode" | "cursor" | "" "" Enables Ctrl+Click to open the element's source in the chosen editor.
showIndicator boolean true When true, shows hover and click overlays on traced DOM elements.
postToParent boolean true When true and inside an iframe, posts indicator-click, indicator-hover, and trace-ready to window.parent. Set to false to disable outbound posts while keeping overlays. The element-click listener is always registered when the page is embedded.

4.3 Start the Dev Server

npm run dev

Svelte Trace only runs during development; it does not affect production builds.

5. How It Works

Svelte Trace injects two data attributes onto every element at compile time:

Before preprocessing:

<div class="container">
    <h1>Hello World</h1>
</div>

After preprocessing:

<div class="container" data-svelte-trace="..." data-svelte-trace-id="st_82hj23af">
    <h1 data-svelte-trace="..." data-svelte-trace-id="st_ab1234ef">Hello World</h1>
</div>
Attribute Contents
data-svelte-trace Base64-encoded string containing source location metadata (file path, line, column, offsets).
data-svelte-trace-id A short, stable ID (e.g. st_82hj23af) derived deterministically from filePath + ":" + tagOffsetStart.

The ID stays stable across recompiles as long as the element's position in the file does not change. If a hash collision occurs within the same document, Svelte Trace automatically extends the hash to ensure uniqueness.

6. Decoding Trace Metadata

6.1 In the Browser

const el = document.querySelector("[data-svelte-trace]");
const decoded = atob(el.getAttribute("data-svelte-trace"));
console.log(decoded);

6.2 In Node.js

const encoded = "dGFnWzI6M10tY2xhc3NbLTE6LTFdLWZbL3BhdGgvc3ZlbHRlXQ==";
const decoded = Buffer.from(encoded, "base64").toString("utf8");
console.log(decoded);

6.3 Decoded Format Reference

The decoded string follows this structure:

tagName[...]-tagLineCol[...]-tagOffset[...]-classOffset[...]-file[...]
Field Example Description
tagName[name] tagName[h1] The element's tag name.
tagLineCol[line:col] tagLineCol[44:4] Line and column of the opening tag. Used by editors to jump to the right position.
tagOffset[start:end] tagOffset[1200:1220] Character offsets of the opening tag's content—the span between < and >. For <h1 class="flex">, this covers h1 class="flex".
classOffset[start:end] classOffset[1263:1350] Character offsets of the class attribute value. Returns -1:-1 only when no class attribute is present. An empty (class="") or bare (class) attribute still returns real offsets.
file[path] file[/src/App.svelte] Absolute path to the source file.

7. Optional Features

7.1 Open in Editor

Enable Ctrl+Click to open an element's source directly in your editor:

svelteTrace({ openInEditor: "vscode" });
svelteTrace({ openInEditor: "cursor" });

7.2 Iframe Integration

Use this when your Svelte app runs inside an iframe—for example, in a visual editor or design tool—and the parent page needs to:

  • Know when the traced DOM has been rebuilt (after Vite HMR or navigation)
  • Re-select the same logical element without requiring a new user click
  • Use fresh trace metadata (tagOffset, classOffset, etc.) after each compile

Communication across the iframe boundary uses postMessage in both directions. Because DOM nodes cannot be passed across the boundary, elements are identified by their id or data-svelte-trace-id.

8. Iframe Message Protocol

8.1 trace-ready (iframe → parent)

Purpose: Notifies the parent that trace-bearing markup in the DOM may have changed. Any cached tagOffset or classOffset from a previous compile should be treated as stale until the next indicator-click (or your own re-parse).

Requirements: postToParent: true and the page must be embedded (window.parent !== window).

When it fires:

  • Once around the window load event (or immediately if the document is already complete when the script initializes)
  • On MutationObserver activity: childList or subtree changes under document.documentElement, or attribute changes on data-svelte-trace / data-svelte-trace-id

Payload:

{ type: "trace-ready", source: "svelte-trace" }

Note: There is no debounce. A single HMR pass can produce multiple trace-ready messages. The parent should coalesce them if needed (e.g. with requestAnimationFrame).

8.2 element-click (parent → iframe)

Purpose: Instructs the iframe to programmatically click a specific element, following the same code path as a real user click—including overlays (if enabled) and outbound indicator-click (if postToParent is true).

Payload:

Field Type Description
type "element-click" Required.
id string | null The element is located via document.getElementById(id) first.
traceId string | null Used when id is null or empty. Looks up [data-svelte-trace-id="…"] via CSS.escape.

Resolution order:

  1. Non-empty idgetElementById
  2. Else non-empty traceIdquerySelector on data-svelte-trace-id
  3. If nothing is found → warns in the console and does nothing

Examples:

// Locate by DOM id
iframe.contentWindow.postMessage(
    { type: "element-click", id: "hero", traceId: null },
    targetOrigin,
);

// Locate by trace id
iframe.contentWindow.postMessage(
    { type: "element-click", id: null, traceId: "st_abcd1234" },
    targetOrigin,
);

8.3 Outbound Messages (iframe → parent)

Sent only when postToParent: true and the page is embedded. Every message includes source: "svelte-trace".

type When it fires Extra fields
trace-ready On load and on trace-related DOM mutations (none)
indicator-click User click, or a successful element.click() triggered by element-click rect, element
indicator-hover Pointer moves over a traced element rect, element

The element object on click and hover events:

Field Present when
tagName, id, className, traceId Always
tagLineCol, tagOffset, classOffset, file When data-svelte-trace decodes successfully

traceId is taken from the nearest [data-svelte-trace] ancestor's data-svelte-trace-id.

9. Runtime Flags & Teardown

The indicator bundle is injected into the root layout whenever any of the following is true: openInEditor is "vscode" or "cursor", showIndicator is true, or postToParent is true.

Before indicator.js runs, these globals are set:

Global Controls
window.__SVELTE_TRACE_SHOW_INDICATOR__ Whether overlay UI is rendered
window.__SVELTE_TRACE_POST_TO_PARENT__ Whether outbound postMessage events are sent

To tear down Svelte Trace at runtime (disconnect observers, remove listeners):

window.__SVELTE_TRACE_DESTROY__?.();

10. Use Cases

  • DevTools — Display source file and line number on hover.
  • Visual Editors — Map DOM selections back to their source location.
  • Automation — Locate and transform source snippets programmatically.
  • Debugging — Build smarter, source-aware Svelte tooling.

11. Contributing

Issues and pull requests are welcome on GitHub.

12. Support

13. License

MIT — see LICENSE.

Built with ❤️ for the Svelte community.

Top categories

Loading Svelte Themes