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

react-insight-overlay

v1.0.0

Published

A lightweight React utility for opt-in contextual explanation overlays

Readme

react-insight-overlay

Add on-demand explanations to any element in your React app — one attribute, zero wrappers, no performance cost when off.

RIO (React Insight Overlay) lets you embed developer-authored context directly into your UI. Toggle insight mode with Alt+I, hover any annotated element, and a smart tooltip appears with rich JSX content, auto-positioned and portal-rendered above everything.

npm install react-insight-overlay

Why RIO

  • Attribute-based. Annotate any element with data-rio and you're done. No component imports, no prop drilling, no refactors.
  • Zero cost when off. When insight mode is disabled, RIO registers zero listeners and renders no DOM. Your app is completely unaffected.
  • Portal above everything. Overlay renders via ReactDOM.createPortal to document.body. Works above AG Grid, Mantine modals, and any z-index stack.
  • Pure CSS theming. Override CSS variables to match your brand. No theme provider, no CSS-in-JS, no runtime cost.
  • Smart tooltip placement. Automatically picks right → left → below → above based on viewport constraints. Supports data-rio-placement hints.
  • Keyboard first. Alt+I to enter, Esc to exit, focus-based navigation for accessible use.
  • Rich content. Tooltip content can be plain strings, JSX, or async functions that fetch docs on demand.

Quick start

1. Wrap your app

import { RioProvider } from 'react-insight-overlay'
import 'react-insight-overlay/rio.css'

export default function App() {
  return (
    <RioProvider>
      <YourApp />
    </RioProvider>
  )
}

2. Annotate elements

The simplest form — pass a string directly:

<button data-rio="Executes trade at current market price">
  Buy
</button>

Or reference a key in a contentMap for rich JSX:

<div data-rio="utilization" data-rio-placement="above" />

3. Toggle it

Press Alt+I anywhere in your app. Hover any annotated element to see its explanation. Press Esc to exit.


Rich content

Pass a contentMap to RioProvider for rich JSX content, with full support for async loaders:

<RioProvider
  contentMap={{
    utilization: (
      <div>
        <strong>Utilization</strong> = capital deployed / total available
        <p>Above 80% may limit new positions.</p>
      </div>
    ),
    riskScore: async () => {
      const docs = await fetchRiskDocs()
      return <MarkdownRenderer source={docs} />
    },
  }}
>
  <YourApp />
</RioProvider>

Co-locate content with the feature

Use useRioContent to register tooltip content directly from the component that owns it — no central map required:

import { useRioContent } from 'react-insight-overlay'

function PortfolioPanel() {
  useRioContent({
    'portfolio-total': (
      <div>
        <strong>Total portfolio value</strong>
        <p>Sum of all holdings at current market price.</p>
      </div>
    ),
  })

  return <div data-rio="portfolio-total">$84,210</div>
}

Custom activation

Default is Alt+I, but you can rebind or use alt-click:

// Different hotkey
<RioProvider activation={{ type: 'hotkey', combo: { ctrl: true, key: '?' } }}>

// Hold Alt and click anywhere to toggle
<RioProvider activation={{ type: 'alt-click' }}>

Programmatic toggle

Expose a button anywhere in your UI with the headless RioToggle:

import { RioToggle } from 'react-insight-overlay'

<RioToggle>
  {({ enabled, toggle }) => (
    <button onClick={toggle}>
      {enabled ? 'Exit help' : '? Help'}
    </button>
  )}
</RioToggle>

Or access the context directly:

import { useRio } from 'react-insight-overlay'

function MyComponent() {
  const { enabled, toggle } = useRio()
  // ...
}

Theming

Override any CSS variable to match your product's identity:

:root {
  --rio-accent:         #d4af37;
  --rio-tooltip-bg:     #0d0900;
  --rio-tooltip-fg:     #fef3c7;
  --rio-tooltip-border: rgba(212, 175, 55, 0.4);
  --rio-mask:           rgba(0, 0, 0, 0.5);
}

Or use one of the built-in themes via overlayClassName:

<RioProvider overlayClassName="rio-theme-gold">
<RioProvider overlayClassName="rio-theme-copper">
<RioProvider overlayClassName="rio-theme-light">

Available CSS variables

--rio-mask
--rio-accent
--rio-accent-glow
--rio-highlight-radius
--rio-highlight-outline
--rio-highlight-glow
--rio-tooltip-bg
--rio-tooltip-fg
--rio-tooltip-muted
--rio-tooltip-border
--rio-tooltip-shadow
--rio-tooltip-radius
--rio-tooltip-hint-color
--rio-font-size
--rio-arrow-size

API

<RioProvider>

| Prop | Type | Default | Description | | ------------------ | --------------------------------- | -------------------------------------- | -------------------------------------------------------- | | children | ReactNode | — | Your app. | | contentMap | RioContentMap | {} | Map of data-rio keys to JSX / async loaders. | | activation | RioActivation | { type: 'hotkey', combo: Alt+I } | How insight mode is toggled. | | dim | boolean | true | Dim the background when active. | | overlayClassName | string | — | Class applied to the overlay root for custom theming. | | portalTarget | HTMLElement | document.body | Where the overlay is portaled. |

data-rio attributes

| Attribute | Value | Description | | --------------------- | --------------------------------- | ----------------------------------------------------------------- | | data-rio | string key or inline text | Lookup key into contentMap, or fallback inline text. | | data-rio-placement | right \| left \| above \| below | Optional placement hint. Smart placement overrides if off-screen. |

Hooks

  • useRio() — returns { enabled, enable, disable, toggle }.
  • useRioContent(map) — register tooltip content from a component, auto-cleaned on unmount.

Components

  • <RioToggle> — headless render-prop toggle.

Do's and don'ts

Do

  • Annotate the things users actually ask about. Interactive controls, metrics, and dense data displays earn their keep. Labels, headings, and decorative chrome usually don't.
  • Answer "what is this and why does it exist?" — not how to click it. UI affordances should already cover the how.
  • Co-locate content with the component that owns it. Reach for useRioContent first; reserve contentMap for page-level chrome (nav, headers, layout shells).
  • Nest RioProviders for self-contained sub-apps or demos. Each one keeps its own scope, and a parent's toggle cascades down — so a single page-level "show insight" button lights everything up at once.
  • Set data-rio-placement near viewport edges. It's a hint, not a hard rule — smart placement still fires if your hint won't fit.
  • Gate it on a flag if RIO is only meant for staff, dev, or beta audiences. Tree-shake the import too if you want zero bytes shipped to the wrong build.

Don't

  • Don't use RIO for tours, onboarding, or marketing pop-ups. It's an opt-in inspector for power users — not always-on UX. If your tooltip needs to fire without user intent, you want a different tool.
  • Don't blanket-annotate. Sparse, deliberate annotations are how RIO stays useful; a data-rio on every div turns insight mode into noise.
  • Don't put expensive work in async contentMap loaders without caching. They run on every hover. Memoize, dedupe, or cache the fetch yourself.
  • Don't expect a parent provider to highlight elements inside a nested provider's subtree. Each provider owns its own scope — the outer overlay deliberately bails when the cursor is inside a child. Move the annotation, or register it via the inner provider, if you need it picked up.
  • Don't rely on Esc to fully exit a cascaded child. Esc only flips the provider whose key listener fired — if a parent is still enabled, the child stays lit by inheritance. Toggle the parent to exit cleanly.
  • Don't reuse data-rio keys as test selectors or style hooks. They're a content-lookup mechanism; collisions are isolated per scope, not unique across the page.

Philosophy

  • Infrastructure > UI library — RIO is a developer-authored context layer, not a tour or tooltip library.
  • CSS > JS theming — pure CSS variables, no runtime overhead.
  • Explicit > magical — one attribute, one overlay, no side effects when disabled.
  • Small surface area — no step engine, no analytics, no CMS, no dependencies.

Monorepo layout

This repository contains both the published library and its marketing/landing site.

rio/
├── src/           # library source (published as react-insight-overlay)
├── landing/       # marketing site (landing page with live demo)
├── index.html     # landing entry
├── vite.config.ts       # landing page build
└── vite.lib.config.ts   # library build

Development

# Install deps
npm install

# Run landing page dev server
npm run dev

# Build the library (→ dist/)
npm run build:lib

# Build the landing page (→ dist-landing/)
npm run build:landing

# Build both
npm run build

# Typecheck
npm run typecheck

Peer dependencies

  • react >= 17
  • react-dom >= 17

License

MIT