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

uidex

v0.0.1

Published

A framework-agnostic library for highlighting and annotating UI elements

Readme

uidex

A React library for highlighting and annotating components. Perfect for building tutorials, onboarding experiences, or debugging tools.

Installation

npm install uidex

Requirements

  • 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 include
  • exclude - Additional exclude patterns for this source only
  • prefix - 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-scan

Adding 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