uidex
v0.0.1
Published
A framework-agnostic library for highlighting and annotating UI elements
Maintainers
Readme
uidex
A React library for highlighting and annotating components. Perfect for building tutorials, onboarding experiences, or debugging tools.
Installation
npm install uidexRequirements
- React 18 or higher
- React DOM 18 or higher
Configuration
Create a .uidex.json file in your project root to customize default settings:
{
"$schema": "./node_modules/uidex/uidex.schema.json",
"defaults": {
"color": "#3b82f6",
"borderStyle": "solid",
"borderWidth": 2,
"showLabel": true,
"labelPosition": "top-left"
},
"colors": {
"primary": "#3b82f6",
"success": "#10b981",
"warning": "#f59e0b",
"error": "#ef4444",
"info": "#6366f1"
},
"disabled": false
}Using the Config Provider
Wrap your app with AnnotateProvider to apply configuration:
import { AnnotateProvider } from 'uidex';
import config from './.uidex.json';
function App() {
return (
<AnnotateProvider config={config}>
{/* Your app */}
</AnnotateProvider>
);
}Named Colors
Use named colors from your config:
<Annotate label="Error" color="error">
<button>Delete</button>
</Annotate>Usage
Annotate Component
Wrap any component with Annotate to add hover-based highlighting:
import { Annotate } from 'uidex';
function App() {
return (
<Annotate label="Submit Button" color="#10b981">
<button>Submit</button>
</Annotate>
);
}Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| children | ReactNode | required | The content to wrap |
| label | string | - | Label text shown on hover |
| color | string | #3b82f6 | Highlight color (hex or named color) |
| borderStyle | 'solid' \| 'dashed' \| 'dotted' | 'solid' | Border style |
| borderWidth | number | 2 | Border width in pixels |
| showLabel | boolean | true | Whether to show the label |
| labelPosition | 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right' | 'top-left' | Label position |
| disabled | boolean | false | Disable highlighting |
| className | string | - | Additional CSS class |
| style | CSSProperties | - | Additional inline styles |
| onHover | (isHovered: boolean) => void | - | Callback on hover state change |
HighlightOverlay Component
For more control, use HighlightOverlay with a ref to any element:
import { useRef } from 'react';
import { HighlightOverlay } from 'uidex';
function App() {
const buttonRef = useRef<HTMLButtonElement>(null);
return (
<>
<button ref={buttonRef}>Click me</button>
<HighlightOverlay
targetRef={buttonRef}
label="Action Button"
color="#f59e0b"
visible={true}
/>
</>
);
}Hooks
useHighlight
Simple state management for highlight visibility:
import { useHighlight } from 'uidex';
function App() {
const { isHighlighted, highlight, unhighlight, toggle } = useHighlight();
return (
<div>
<button onClick={toggle}>Toggle Highlight</button>
{isHighlighted && <div>Highlighted!</div>}
</div>
);
}useAnnotation
Combines a ref with highlight state:
import { useAnnotation, HighlightOverlay } from 'uidex';
function App() {
const { ref, isHighlighted, toggle } = useAnnotation();
return (
<>
<div ref={ref}>Target element</div>
<button onClick={toggle}>Toggle</button>
<HighlightOverlay targetRef={ref} visible={isHighlighted} label="Target" />
</>
);
}useAnnotateConfig
Access the current configuration:
import { useAnnotateConfig } from 'uidex';
function MyComponent() {
const config = useAnnotateConfig();
console.log(config.defaults?.color); // Current default color
console.log(config.colors?.primary); // Named color value
}Build-Time Scanner
The uidex-scan CLI tool scans your source files for data-uidex attributes and generates a TypeScript registry file. This enables type-safe access to all annotations in your codebase.
Setup
Add scanner configuration to your .uidex.json:
{
"$schema": "./node_modules/uidex/uidex.schema.json",
"scanner": {
"include": ["**/*.tsx"],
"exclude": ["**/*.test.*", "**/*.spec.*", "**/generated/**"],
"outputPath": "src/generated/annotations.ts",
"rootDir": "src"
}
}Note: The include and exclude patterns are relative to rootDir. If rootDir is src, use patterns like **/*.tsx (not src/**/*.tsx).
Monorepo Support
For monorepos with multiple packages, use the sources array to scan multiple directories:
{
"$schema": "./node_modules/uidex/uidex.schema.json",
"scanner": {
"sources": [
{
"rootDir": "src",
"include": ["**/*.tsx"]
},
{
"rootDir": "../packages/ui/src",
"include": ["**/*.tsx"],
"prefix": "@myorg/ui"
},
{
"rootDir": "../packages/components/src",
"include": ["**/*.tsx"],
"exclude": ["**/internal/**"],
"prefix": "@myorg/components"
}
],
"exclude": ["**/*.test.*", "**/*.spec.*", "**/generated/**"],
"outputPath": "src/generated/annotations.ts"
}
}Each source can have:
rootDir- Directory to scan (can be relative path like../packages/ui)include- Glob patterns for files to includeexclude- Additional exclude patterns for this source onlyprefix- Optional prefix for file paths in output (e.g.,@myorg/ui/Button.tsx)
The exclude at the top level applies globally to all sources.
Usage
Run the scanner as part of your build process:
// package.json
{
"scripts": {
"prebuild": "npx uidex-scan",
"build": "next build"
}
}Or run it directly:
npx uidex-scanAdding Annotations
Add data-uidex attributes to your JSX elements:
<nav data-uidex="main-nav">
<a href="/">Home</a>
</nav>
<button data-uidex="cta-button">Click Me</button>Generated Output
The scanner generates a TypeScript file with all discovered annotations:
// Auto-generated by uidex scanner
// Do not edit this file manually
export const annotations = {
"cta-button": [{ filePath: "src/pages/Home.tsx", line: 12 }],
"main-nav": [{ filePath: "src/components/Header.tsx", line: 5 }]
} as const;
export const annotationIds = ["cta-button", "main-nav"] as const;
export type AnnotationId = typeof annotationIds[number];Using Generated Types
Import the generated types for type-safe annotation access:
import { annotations, AnnotationId } from './generated/annotations';
function highlightElement(id: AnnotationId) {
const locations = annotations[id];
console.log(`Found at: ${locations[0].filePath}:${locations[0].line}`);
}
// Type error: "invalid-id" is not a valid AnnotationId
highlightElement("invalid-id");TypeScript
This package is written in TypeScript and includes full type definitions. All types are exported:
import type {
AnnotateProps,
AnnotateProviderProps,
BorderStyle,
HighlightOverlayProps,
LabelPosition,
ReactAnnotateConfig,
ReactAnnotateDefaults,
UseAnnotationOptions,
UseHighlightOptions,
} from 'uidex';License
MIT
