@upgraide/ui-notes-react
v0.2.7
Published
React components for UI Notes - capture and display UI feedback annotations
Maintainers
Readme
@upgraide/ui-notes-react
Drop-in React component that adds visual feedback annotations to any page.
Installation
npm install -D @upgraide/ui-notes-reactThis is a development/QA tool — install it as a dev dependency so it doesn't ship in your production bundle.
Peer dependencies: React 18 or 19
Quick Start
import { UINotes } from "@upgraide/ui-notes-react";
function App() {
return (
<>
<YourApp />
<UINotes
apiUrl="https://your-api.example.com"
apiKey="your-api-key"
project="my-app"
/>
</>
);
}That's it. A floating button appears in the bottom-right corner. Click it to open the notes panel or start annotating elements on the page.
Production: See Disabling in Production to make sure the component is fully excluded from production builds.
How It Works
- Toggle — Click the floating button to open the panel
- Annotate — Click "Start Annotating", hover over elements to highlight them, click one to open the note form
- Submit — Pick a type (Bug, UX Issue, Feature Request, or Question), write a description, and submit
- View — Colored markers appear on annotated elements. Click them to see details, or browse all notes in the panel
Props
| Prop | Type | Description |
|------|------|-------------|
| apiUrl | string | Base URL of your UI Notes API server |
| apiKey | string | API key for authentication |
| project | string | Project slug to scope notes to |
Note Types
| Type | Color | |------|-------| | Bug | Red | | UX Issue | Orange | | Feature Request | Blue | | Question | Purple |
Keyboard Shortcuts
| Key | Action |
|-----|--------|
| Ctrl+Shift+A / Cmd+Shift+A | Toggle annotation mode on/off |
| Ctrl+Shift+Z / Cmd+Shift+Z | Toggle show notes on page |
| Escape | Close form or tooltip |
| Ctrl+Enter / Cmd+Enter | Submit note |
Element Detection
When you annotate an element, the component automatically captures:
- Component name — from
data-componentordata-testidattributes - CSS selector — prefers
data-testid, thenid, then tag+class combinations - Text content — first 100 characters of the element's text
- URL — current page URL
- HTML tag — the element's tag name
Add data-component or data-testid attributes to your elements for better annotation labels.
Exports
Components
UINotes— Main component (default). Renders the widget and annotation layer.
API Client
import { UINotesAPI } from "@upgraide/ui-notes-react";
const api = new UINotesAPI("https://api.example.com", "your-key", "my-project");
const notes = await api.getNotes("open");
await api.createNote({ type: "bug", body: "Button is broken", ...elementData });Types
import type { Note, CapturedElement, UINoteProps } from "@upgraide/ui-notes-react";Note— Full note object withid,type,body,status,selector,component, etc.CapturedElement— Data captured from an annotated DOM elementUINoteProps— Props for theUINotescomponent
Utilities
import { captureElement, detectComponent, generateSelector, timeAgo } from "@upgraide/ui-notes-react";captureElement(el)— Extract metadata from a DOM elementdetectComponent(el)— Find component name from data attributesgenerateSelector(el)— Create a CSS selector for an elementtimeAgo(dateStr)— Format a date string as relative time (e.g. "2 hours ago")
Styling
All styles are self-contained — no CSS imports needed. The component uses inline styles and renders via React portals to avoid layout interference with your app.
Disabling in Production
Since this is a dev/QA tool, you'll want to exclude it from production builds entirely. There are a few approaches:
Environment variable check
{process.env.NODE_ENV !== "production" && (
<UINotes apiUrl="..." apiKey="..." project="..." />
)}Most bundlers (Vite, webpack, Next.js) will tree-shake the component out of production builds when using process.env.NODE_ENV.
Feature flag
Use a dedicated env variable for more control (e.g. enable in staging but not production):
{process.env.NEXT_PUBLIC_UINOTES_ENABLED === "true" && (
<UINotes apiUrl="..." apiKey="..." project="..." />
)}Dynamic import
To avoid loading the module at all in production:
import { lazy, Suspense } from "react";
const UINotes = lazy(() => import("@upgraide/ui-notes-react"));
function App() {
return (
<>
<YourApp />
{process.env.NODE_ENV !== "production" && (
<Suspense fallback={null}>
<UINotes apiUrl="..." apiKey="..." project="..." />
</Suspense>
)}
</>
);
}Framework Notes
Next.js
Environment variables used in client-side code must be prefixed with NEXT_PUBLIC_:
NEXT_PUBLIC_UINOTES_API_URL=https://your-api.example.com
NEXT_PUBLIC_UINOTES_API_KEY=your-api-key
NEXT_PUBLIC_UINOTES_ENABLED=true{process.env.NEXT_PUBLIC_UINOTES_ENABLED === "true" && (
<UINotes
apiUrl={process.env.NEXT_PUBLIC_UINOTES_API_URL}
apiKey={process.env.NEXT_PUBLIC_UINOTES_API_KEY}
project="my-app"
/>
)}The component must be used in a Client Component (add "use client" at the top of the file).
Vite
Vite exposes env variables prefixed with VITE_:
VITE_UINOTES_API_URL=https://your-api.example.com
VITE_UINOTES_API_KEY=your-api-key<UINotes
apiUrl={import.meta.env.VITE_UINOTES_API_URL}
apiKey={import.meta.env.VITE_UINOTES_API_KEY}
project="my-app"
/>Build from Source
cd packages/react
bun install
bun run buildOutput goes to dist/ — ES module + CommonJS + TypeScript declarations.
License
MIT
