uiref Svelte Themes

Uiref

Point at UI elements in your running web app, send structured references to Claude Code. Chrome extension + Svelte/React/Vue/Angular build plugins.

uiref

Stop saying "which button?" to Claude.

Click any UI element in your running web app → Claude gets the exact source file, line, component, and surrounding context. Built for dense dashboards, unfamiliar codebases, and multi-component bug reports where "fix this" is ambiguous.

Chrome extension + Svelte / React / Vue / Angular build plugins. Local-only. MIT.

Install · How it works · Who is this for? · Spec · Troubleshooting


Who is this for?

You'll get 10x value if:

  • You work on a dense app — dashboards, admin panels, design systems with 50+ components
  • Your codebase has many similar elements — a dozen chart widgets, identical-looking buttons in different contexts, nested wrapper components
  • You use third-party component libraries (shadcn, bits-ui, Radix, MUI) and open them rarely
  • You ship SvelteKit / Next.js / Nuxt / Angular apps where route state matters
  • You debug with GraphQL and need to know which operations a click fires
  • You want PMs, designers, or QA to point at UI in bug reports without knowing the code

You probably don't need this if:

  • Your app is a small landing page with obvious component names
  • You're writing components you know cold — typing src/Header.tsx is faster than the capture workflow
  • Your changes are "make it red" level — capture overhead ≈ chat overhead

The honest caveat: uiref tells Claude where, never what. You still articulate the change in chat. This is the design: location from the tool, intent from the conversation. Tools that try to infer intent from clicks guess badly.

The problem

When you tell an AI coding assistant "fix this button" or "change that header," it has to guess which component you mean. In a codebase with dozens of generic wrappers (Card, EchartsWrapper, Button), the guess is often wrong — you spend your turn explaining location instead of intent.

Sending a screenshot doesn't fix this. Even frontier vision models drift 5–30 pixels on coordinate regression, and a screenshot shows the AI what the element looks like, not which source file rendered it.

uiref turns ambiguous deictic pronouns ("this," "that") into structured references.

How it works

┌──────────────────────────────────────┐
│  Your app (React / Vue / Svelte /    │
│  Angular) with the uiref build       │
│  plugin installed. DOM elements get  │
│  data-uiref-file / -line / -component│
│  attributes at compile time.         │
└──────────────────┬───────────────────┘
                   │
         ⌘⇧C · click an element
                   │
                   ▼
┌──────────────────────────────────────┐
│  uiref Chrome extension              │
│    • hover-to-highlight picker       │
│    • reads data-uiref-* attrs        │
│    • screenshots the element         │
│    • writes uiref/v1 JSON to inbox   │
└──────────────────┬───────────────────┘
                   │
                   │  ~/uiref-inbox/<timestamp>.uiref.json
                   ▼
┌──────────────────────────────────────┐
│  Claude Code + uiref skill           │
│    • detects UI-reference language   │
│    • reads the latest uiref          │
│    • edits target.file:line directly │
└──────────────────────────────────────┘

The flow:

you:    [click SaveButton in browser]
        [switch to Claude Code]
        "make this use the danger variant"

claude: I see you pointed at <SaveButton> at
        src/components/SaveButton.tsx:42. Applying now.
        [edits the exact file]

Where it really shines

Dense dashboards. You have a water-consumption dashboard with 15 widget types. "Fix this chart" is ambiguous. Click it → Claude gets WaterConsumptionChart.svelte:42 and the parent InsightsPage.svelte:120 that configures it. Zero back-and-forth.

Third-party components. "Why is this popover cropped?" on a bits-ui dropdown you've never opened. uiref resolves to the wrapper + your usage site + computed styles. Claude finds the overflow issue without grep.

Bug reports with receipts. Workflow mode captures N clicks, the events (console errors, failed network requests, SPA navigations) between them, and the URL at each step. "This broke somewhere during the signup flow" becomes a replayable, timestamped JSON Claude can reason about directly.

Cross-role collaboration. PMs and designers can capture and hand off without touching code.

What you get

  • Precise targeting. Source file, line number, component name — no guessing.
  • Framework-aware. Works with Svelte 4/5, React, Vue 3, Angular 17+.
  • Production-safe. Build plugins opt-in per environment; ship clean HTML to production if you want.
  • Local only. Screenshots and DOM data never leave your machine. No accounts, no cloud, no telemetry.
  • Resilient to framework updates. Data attributes are injected at build time, so the mechanism doesn't depend on React's _debugSource or Svelte's internal APIs (which break across versions).
  • Open protocol. Every component of the system — build plugins, extension, skill — is independent. The uiref/v1 JSON format is the contract; any tool can produce or consume it.

Install (60 seconds)

Step 1 — Run the setup CLI in your project root

npx @uiref/setup

Auto-detects your framework (Svelte / React / Vue / Angular) and package manager, installs the matching @uiref/* plugin, patches your build config, copies the Claude Skill to ~/.claude/skills/uiref/, and creates ~/uiref-inbox/. ~20 seconds.

Step 2 — Install the Chrome extension

  1. Download uiref-extension-v0.2.0.zip from the latest release (~30 KB)
  2. Unzip it somewhere stable (e.g. ~/uiref-extension/)
  3. Open chrome://extensions/ → toggle Developer mode (top-right) → Load unpacked → select the unzipped folder

(Chrome Web Store submission is in progress — once approved, this becomes a one-click install.)

Step 3 — Restart your dev server, start picking

⌘⇧C (Mac) / Ctrl+Shift+C (Win/Linux) on any page you're dev-serving → click an element → the extension writes a uiref JSON to ~/uiref-inbox/. Switch to Claude Code, say "fix this" — Claude reads the inbox automatically.

On first capture the browser will ask you to pick an inbox folder once; choose ~/uiref-inbox/.

Manual install (if you prefer)

If you'd rather not use the setup CLI, install the plugin yourself. You'll also need to copy the Claude Skill manually (the CLI does this for you):

mkdir -p ~/.claude/skills/uiref
curl -fsSL https://raw.githubusercontent.com/KokXinTan/uiref/main/skill/SKILL.md \
  -o ~/.claude/skills/uiref/SKILL.md
mkdir -p ~/uiref-inbox

Then pick your framework:

Svelte 4 / Svelte 5 (SvelteKit)
npm install --save-dev @uiref/svelte
// svelte.config.js
import uiref from '@uiref/svelte';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';

export default {
  preprocess: [uiref(), vitePreprocess()],
  // ...rest of your config
};

The preprocessor runs dev-only by default. Restart your dev server after adding it.

React (any bundler with Babel)
npm install --save-dev @uiref/babel-plugin-react

For Vite + React:

// vite.config.js
import react from '@vitejs/plugin-react';

export default {
  plugins: [
    react({
      babel: {
        plugins: [
          ['@uiref/babel-plugin-react', { enabled: process.env.NODE_ENV !== 'production' }],
        ],
      },
    }),
  ],
};

For Next.js / Create React App: see plugins/react/README.md.

Also copy the Claude Skill:

mkdir -p ~/.claude/skills/uiref
curl -fsSL https://raw.githubusercontent.com/KokXinTan/uiref/main/skill/SKILL.md -o ~/.claude/skills/uiref/SKILL.md
Vue 3 (Vite)
npm install --save-dev @uiref/vue
// vite.config.js
import vue from '@vitejs/plugin-vue';
import uirefVue from '@uiref/vue';

export default {
  plugins: [
    uirefVue(),  // must come before vue()
    vue(),
  ],
};
Angular 17+
npm install --save-dev @uiref/angular

See plugins/angular/README.md for the Vite integration.

3. Install the Claude Skill

The skill teaches Claude Code to automatically check the uiref inbox when you reference a UI element.

git clone https://github.com/KokXinTan/uiref.git /tmp/uiref
mkdir -p ~/.claude/skills/uiref
cp /tmp/uiref/skill/SKILL.md ~/.claude/skills/uiref/SKILL.md

Restart Claude Code. Verify by asking Claude "what skills do you have?" — uiref should be in the list.

4. Set up your inbox folder

mkdir -p ~/uiref-inbox

On first capture, the extension will prompt you to pick this folder. Select ~/uiref-inbox. The extension remembers the choice, so you only do this once.

By default, the extension only starts buffering events (console logs, errors, network) once you activate the picker on a tab. For your own projects, you probably want eager buffering (full pre-click history) and GraphQL operation-name extraction (so repeated calls to /graphql are distinguishable).

Add to your app's bootstrap:

if (import.meta.env.DEV && typeof window !== 'undefined') {
  window.__uirefConfig = {
    eagerPatch: true,                 // buffer events from page load
    captureGraphQLOperation: true,    // extract GraphQL operationName from POST bodies
  };
}

Safe in production. import.meta.env.DEV is a compile-time constant in Vite. vite build (any --mode) sets it to false, so Rollup's dead-code elimination strips the entire block from the production bundle. The shipped JS contains zero uiref code — no __uirefConfig, no config object, nothing. Verified by grepping the build output.

SvelteKit users: for cleanest placement, use src/hooks.client.ts (runs before any route). For other frameworks:

  • React (Vite) — top of src/main.tsx, before createRoot()
  • Next.js — top of app/layout.tsx (client component) or in a <Script> in app.html
  • Vue — top of src/main.ts, before app.mount()
  • Angular — top of src/main.ts, before bootstrapApplication()

Why this works even though inject.js runs before your app: the extension re-reads window.__uirefConfig dynamically on every event emission, not just at page load. So setting the config late (after your app has started) still enables capture for subsequent events.

See full config options in the spec.

Your first capture

  1. Start your dev server — verify the app runs and reloads normally.
  2. Open the page in Chrome.
  3. Press ⌘⇧C (Mac) or Ctrl+Shift+C (Windows/Linux).
  4. Hover elements — each shows its component name and source location in a floating label.
  5. Click any element. A toast appears bottom-right: <SaveButton> → Claude.
  6. Switch to Claude Code and say:

    "make this red" — or — "explain what this does" — or — "move this to the top"

Claude reads ~/uiref-inbox/ and knows the exact component. It acknowledges the reference and edits the right file on the first try.

Keyboard shortcuts

Shortcut Action
⌘⇧C / Ctrl+Shift+C Activate picker
Click Capture the hovered element
Esc Cancel the picker
Select the parent element
Select the first child element

Troubleshooting

The picker does nothing when I press ⌘⇧C or click "Start picker"

Chrome only injects content scripts into tabs loaded after the extension was installed or reloaded. Refresh the tab (⌘R) and try again. If that still doesn't work, open DevTools on the target page and check the Console for errors.

The directory picker can't find ~/.claude/uiref-inbox/

The .claude folder is hidden in macOS Finder. Use ~/uiref-inbox/ (no dot) as the default location — that's what the skill looks in. If you really want the hidden folder, press ⌘⇧. in the Finder dialog to show hidden files.

<svelte:head> cannot have attributes compile error

You're on an older version of @uiref/svelte (pre-0.1.1). Update: npm install -D @uiref/svelte@latest.

Expected token > / parse errors in my Svelte components

You're on an older version of @uiref/svelte that didn't handle {(v) => v} style attribute expressions. Update: npm install -D @uiref/svelte@latest.

pnpm install fails or my dev server can't find @uiref/svelte

Use the npm version (npm install --save-dev @uiref/svelte) unless you're actively developing the plugin itself.

Claude doesn't detect my uiref after I capture

Checks:

  1. Does the file appear in ~/uiref-inbox/? (ls ~/uiref-inbox) If not, the extension didn't write — check that you picked the right folder in the extension's first-run dialog.
  2. Does Claude Code have the uiref skill installed? Ask Claude: "what skills do you have?" — uiref should be listed.
  3. Is your message UI-referential? The skill triggers on "this/that" pronouns and UI verbs. Explicit: "use the uiref I just sent."

The inbox keeps growing

It shouldn't — the extension auto-deletes uiref files older than 1 hour on each new capture, and the skill deletes files after using them. If it's still growing, you probably have uirefs captured in the last hour that the skill hasn't consumed. They'll auto-clean on the next capture cycle.

Repo layout

uiref/
├── SPEC.md                  # uiref/v1 JSON format specification
├── PRIVACY.md               # what data the tool handles and where
├── extension/               # Chrome extension (MV3, vanilla JS)
├── plugins/
│   ├── svelte/              # @uiref/svelte — Svelte preprocessor
│   ├── react/               # @uiref/babel-plugin-react
│   ├── vue/                 # @uiref/vue — Vite plugin
│   └── angular/             # @uiref/angular — Vite plugin
├── skill/                   # Claude Skill (copy to ~/.claude/skills/uiref/)
├── docs/
│   ├── design.md            # Architecture and rationale
│   └── chrome-web-store.md  # Submission checklist
└── CHANGELOG.md

Status

  • Extension: v0.2.0 shipped as a GitHub release, download the zip. Chrome Web Store submission coming.
  • npm packages: all five live at 0.1.0 under the @uiref scope:
  • Svelte plugin: dogfooded on a real SvelteKit app. Handles <svelte:*> elements, self-closing components, arrow-function attributes, tags every HTML element, and skips node_modules/.
  • React, Vue, Angular plugins: v0.1. Tested on synthetic fixtures. Expect edge cases on real codebases — please file issues.

Alternatives considered

Tool What it does Why uiref is different
React DevTools Inspects React components in the browser No structured output for AI; React-only
LocatorJS, click-to-component Click → open in editor Different target: editor vs AI. uiref produces a protocol any AI can consume
Claude for Chrome Agentic browser automation Doesn't resolve DOM → source. Complementary to uiref
Claude Design Design tool for generating prototypes Different workflow (design → code handoff), not running-app → source
ML annotation tools (LabelImg, CVAT, etc.) Label images for ML training Wrong output format, wrong audience

Contributing

Issues and feature requests welcome. Priority contributions:

  • Firefox port of the extension
  • Additional framework plugins (Solid, Qwik, Lit, Stencil)
  • Webpack loader for React projects not on Vite
  • Edge-case bug reports from real codebases (with a minimal repro)

See CONTRIBUTING.md for plugin development guidelines.

License

MIT

Top categories

Loading Svelte Themes