npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pro-ui-feedbacks

v0.3.1

Published

Annotate any website, generate structured visual feedback for AI agents — works as React component or standalone embed

Readme

npm version bundle size license

Why pro-ui-feedbacks?

Screenshots lack context. Text descriptions are ambiguous. AI agents need structured data to act on your UI feedback.

| Method | What AI gets | What's missing | |--------|-------------|----------------| | Screenshot | Pixels | No selectors, no DOM structure — AI guesses | | Copy HTML from DevTools | Raw markup | Too much noise, no annotations | | Text description | "the blue button on the right" | Ambiguous, no coordinates | | pro-ui-feedbacks | CSS selector + DOM path + metadata + annotation + order | Nothing — structured & actionable |

How It Works

  1. Annotate — click any element on your page. The tool captures its CSS selector, DOM path, bounding box, accessibility data, and nearby context. Type your feedback note.
  2. Copy — press ⌘⇧C. All annotations are formatted as structured markdown and copied to your clipboard.
  3. Paste to AI — paste into Claude, ChatGPT, Cursor, or any AI agent. It knows exactly which elements you're referring to, their properties, and what you want changed. No guessing.

Output Example

When you copy feedbacks, AI receives structured markdown like this:

## Page Feedback: /dashboard

**Viewport:** 1440×900

### 1. button: "Submit Order"
**Location:** .checkout-form > .actions > button.btn-primary
**Position:** 892px, 1247px (120×40px)
**Feedback:** Change button color from blue to green for better conversion

### 2. heading: "Order Summary"
**Location:** .sidebar > h2.summary-title
**Position:** 1080px, 200px (300×32px)
**Feedback:** Font size too small on mobile — increase to 18px

Switch to debug mode for even richer output: full DOM paths, computed styles, annotation coordinates, viewport info, and device pixel ratio.

Features

  • AI-Ready Element Capture — hover to highlight any DOM element, click to annotate. Captures CSS selectors, DOM paths, accessibility attributes, computed styles, bounding boxes, and nearby elements — so AI knows exactly which element you mean
  • Ordered Annotations — numbered step markers pinned to elements. AI follows your feedback in sequence. Markers survive scroll and resize; click to edit in-place
  • AI-Optimized Output — two modes: detailed (compact markdown with selector, location, position) or debug (full markdown with environment, DOM path, computed styles, annotation coordinates)
  • Multi-Element Selection — drag to select multiple elements and annotate as a group. Describe component-level issues to AI with one annotation
  • Lightweight Widget — collapsible floating toolbar with start/stop, feedback list, copy, delete, settings, and close. Shows badge count when collapsed
  • Session Persistence — opt-in localStorage persistence so feedbacks survive page reload, with orphan detection for missing elements
  • Keyboard-First Workflow⌘⇧F toolbar, ⌘⇧I inspector, ⌘⇧C copy, ⌘⇧L list, [/] navigate markers, and more
  • Built-in Themes — dark and light themes, zero CSS required (all styles are inline)
  • Tiny Footprint — ~14 kB minified React package, ~76 kB standalone embed. Zero runtime dependencies
  • Fully Typed — written in TypeScript with exported types for every prop and callback
  • SPA Aware — auto-resets inspector and popups on route changes
  • Portal-Based — renders via createPortal so it never conflicts with your app's layout or z-index

Get Started — React

npm install pro-ui-feedbacks lucide-react

react and react-dom (v18 or v19) are required as peer dependencies.

import { ProUIFeedbacks } from 'pro-ui-feedbacks'

function App() {
  return (
    <>
      {/* your app */}
      <ProUIFeedbacks
        onFeedbackSubmit={(fb) => console.log('New feedback:', fb)}
        onFeedbackDelete={(id) => console.log('Deleted:', id)}
      />
    </>
  )
}

The toolbar appears as a collapsed floating button (bottom-right by default). Click it to expand, hit Start to activate the inspector, then click any element to leave feedback.

Get Started — Any Website

Drop a single script tag on any site — HTML, WordPress, Vue, Angular, or anything else. No build tools required.

Web Component

<script src="https://unpkg.com/pro-ui-feedbacks/dist/embed.global.js"></script>
<pro-ui-feedbacks position="bottom-right" theme="dark" persist></pro-ui-feedbacks>

Imperative API

<script src="https://unpkg.com/pro-ui-feedbacks/dist/embed.global.js"></script>
<script>
  const widget = ProUIFeedbacks.init({
    position: 'bottom-right',
    theme: 'dark',
    persist: 'my-session'
  });

  // Later: widget.destroy();
</script>

Custom Element Attributes

| Attribute | Type | Default | Description | |-----------|------|---------|-------------| | position | string | 'bottom-right' | Toolbar position | | theme | string | 'dark' | Color theme ('dark' or 'light') | | z-index | number | 9999 | Base z-index | | collapsed | boolean | true | Start collapsed | | persist | boolean\|string | — | Enable localStorage persistence |

Events (Custom Element)

const widget = document.querySelector('pro-ui-feedbacks');

widget.addEventListener('toggle', (e) => console.log('Active:', e.detail.active));
widget.addEventListener('feedback-submit', (e) => console.log('Feedback:', e.detail.feedback));
widget.addEventListener('feedback-delete', (e) => console.log('Deleted:', e.detail.feedbackId));
widget.addEventListener('copy', () => console.log('Copied'));

WordPress Integration

<!-- Add to theme footer or Custom HTML widget -->
<script src="https://unpkg.com/pro-ui-feedbacks/dist/embed.global.js"></script>
<script>
  ProUIFeedbacks.init({
    position: 'bottom-right',
    theme: 'dark',
    persist: 'wp-feedback'
  });
</script>

Bundle size: ~76KB gzip (includes React runtime, fully self-contained)

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | position | 'bottom-right' \| 'bottom-left' \| 'top-right' \| 'top-left' | 'bottom-right' | Toolbar position on the viewport | | theme | 'dark' \| 'light' | 'dark' | Color theme | | defaultCollapsed | boolean | true | Start with toolbar collapsed | | zIndex | number | 9999 | Base z-index for all layers | | triggerIcon | ReactNode | <Menu /> | Custom icon for the trigger button | | style | CSSProperties | — | Additional inline styles for the container | | persist | boolean \| string | — | Enable localStorage persistence. true = per-page key, string = custom key |

Callbacks

| Prop | Type | Description | |------|------|-------------| | onToggle | (active: boolean) => void | Inspector started or stopped | | onInspect | (element: InspectedElement) => void | Element selected via inspector | | onFeedbackSubmit | (feedback: FeedbackItem) => void | Feedback annotation submitted | | onFeedbackDelete | (feedbackId: string) => void | Feedback marker deleted | | onFeedbackUpdate | (feedbackId: string, content: string) => void | Feedback text edited | | onFeedback | () => void | "Feedbacks" toolbar button clicked | | onCopy | () => void | "Copy" toolbar button clicked | | onDelete | () => void | "Delete All" toolbar button clicked | | onSettings | () => void | "Settings" toolbar button clicked |

Types

interface ElementAccessibility {
  role?: string
  label?: string
  description?: string
}

interface ElementMetadata {
  accessibility: ElementAccessibility
  boundingBox: { x: number; y: number; width: number; height: number }
  computedStyles: Record<string, string>
  cssClasses: string[]
  elementDescription: string   // e.g. `paragraph: "Some text..."`
  elementPath: string          // short class-based CSS path
  fullPath: string             // full tag+class CSS path
  isFixed: boolean
  nearbyElements: string
  nearbyText: string
}

interface InspectedElement {
  element: HTMLElement
  tagName: string
  className: string
  id: string
  selector: string             // generated CSS selector
  rect: DOMRect
  dimensions: { width: number; height: number }
  metadata: ElementMetadata    // rich element metadata
}

interface FeedbackItem {
  id: string
  stepNumber: number           // 1-based
  content: string              // user-entered text
  selector: string             // CSS selector of target element
  offsetX: number              // offset from element's top-left
  offsetY: number
  pageX: number                // absolute page X coordinate
  pageY: number                // absolute page Y coordinate
  targetElement: HTMLElement | null
  element: InspectedElement | null
  createdAt: number            // timestamp
  orphan?: boolean             // true when element not found after reload
  areaData?: AreaData          // area metadata for multi-select
  isAreaOnly?: boolean         // true if annotation on empty space
  elements?: InspectedElement[] // all elements in multi-select group
}

interface AreaData {
  centerX: number              // absolute page X of area center
  centerY: number              // absolute page Y of area center
  width: number                // area width in pixels
  height: number               // area height in pixels
  elementCount: number         // total elements in group
}

type ToolbarPosition = 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
type ToolbarTheme = 'dark' | 'light'

All types are exported from the package entry point, including ElementMetadata, ElementAccessibility, SerializedFeedbackItem, AreaData, AreaBounds, and InspectAreaEvent.

Detailed Usage

Step-by-step

  1. Expand the floating toolbar by clicking the trigger button
  2. Start the inspector — your cursor becomes a crosshair, and elements highlight on hover with a selector + dimensions tooltip
  3. Click an element to open a feedback popover anchored at the click position
  4. Type your note and press Cmd+Enter (or click Submit)
  5. A numbered marker appears pinned to that element — it follows scroll and resize
  6. Hover a marker to preview the note, click it to edit
  7. Stop the inspector or Close the toolbar when done

Area Selection (Multi-Element)

Drag to select multiple elements and annotate them as a group:

  1. Start the inspector
  2. Drag across multiple elements (or empty space)
  3. Release to open feedback popover
  4. Submit — a single marker appears at the area center showing element count

Features:

  • Marker shows step number (same as single-element markers)
  • Hover marker to see element count and tag names
  • Click to edit — shows collapsible element list in edit popup
  • Delete removes the entire group as one feedback item
  • Partial orphan support: elements that disappear after reload are excluded from the resolved list
  • Empty space annotation: drag on empty area to leave contextual feedback (no element data)

Limits:

  • Max 50 elements per selection (for performance)
  • All elements share the same feedback text

Keyboard Shortcuts

| Shortcut | Action | |----------|--------| | ⌘⇧F | Toggle toolbar | | ⌘⇧I | Toggle inspector | | ⌘⇧C | Copy all feedbacks | | ⌘⇧L | Open feedback list | | ⌘⇧, | Open settings | | ⌘⇧⌫ | Delete all feedbacks | | ⌘Z | Undo last delete | | [ / ] | Navigate between markers | | Enter | Edit focused marker | | Escape | Close popups → stop inspector → deselect marker → collapse toolbar |

On Windows/Linux, use Ctrl instead of .

Examples

Light theme, top-left

<ProUIFeedbacks position="top-left" theme="light" />

Collect all feedbacks on submit

function ReviewPage() {
  const feedbacks = useRef<FeedbackItem[]>([])

  return (
    <>
      <ProUIFeedbacks
        onFeedbackSubmit={(fb) => feedbacks.current.push(fb)}
        onCopy={() => {
          const data = feedbacks.current.map((fb) => ({
            step: fb.stepNumber,
            note: fb.content,
            selector: fb.selector,
          }))
          navigator.clipboard.writeText(JSON.stringify(data, null, 2))
        }}
      />
    </>
  )
}

Persist feedbacks across reloads

// Auto per-page key (based on pathname)
<ProUIFeedbacks persist />

// Custom storage key
<ProUIFeedbacks persist="my-review-session" />

When persist is enabled, feedbacks are saved to localStorage and restored on page reload. If a target element can no longer be found in the DOM, its marker is displayed as an orphan with a warning indicator.

Custom trigger icon

import { Bug } from 'lucide-react'

<ProUIFeedbacks triggerIcon={<Bug size={18} />} />

Compatibility

React Package:

  • React 18 or 19
  • Works with Next.js (App Router & Pages Router), Vite, CRA, Remix, and any React setup
  • ESM and CommonJS builds included
  • TypeScript declarations included

Embeddable Script:

  • Any website (no build tools required)
  • Chrome 80+, Firefox 75+, Safari 13.1+, Edge 80+
  • Shadow DOM for style isolation
  • ~76KB gzip (includes React runtime)

Roadmap

  • [ ] MCP (Model Context Protocol) server — AI agents read feedbacks directly
  • [ ] Webhook integration — push feedbacks to any endpoint
  • [ ] JSON output format — alongside markdown
  • [ ] CLI tool — capture feedbacks from terminal

Development

git clone https://github.com/bienhoang/pro-ui-feedbacks.git
cd pro-ui-feedbacks
npm install

npm run dev      # watch mode
npm run build    # production build
npm run typecheck

License

MIT