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

@usefy/use-focus-within

v0.25.1

Published

A React hook that tracks whether keyboard focus is anywhere within a subtree — focusin/focusout based, SSR-safe, with onFocus/onBlur edge callbacks

Readme


Overview

useFocusWithin is part of the @usefy ecosystem — a collection of production-ready, TypeScript-first, SSR-safe React hooks. It tells you, as React state, whether keyboard focus is currently on a container or any of its descendants — the reactive, state-driven equivalent of the CSS :focus-within pseudo-class.

Attach the returned callback ref to any element and read the boolean: highlight a form while it's being filled in, reveal a toolbar while a field group is active, or fire side effects when focus enters/leaves a region.

It's built on the bubbling focusin / focusout events (the non-bubbling focus / blur can't observe descendant focus), and correctly distinguishes focus moving between descendants — where focused stays true with no flicker — from focus leaving the subtree entirely, where it flips to false.

Features

  • [ref, focused] tuple — attach the callback ref, read the boolean; no wiring
  • No flicker — focus moving between two children keeps focused true (unlike naïve focus/blur tracking)
  • Robust relatedTarget: null handling — some browsers report a null relatedTarget even when focus stays inside; the hook defers to document.activeElement on the next microtask to decide correctly
  • Edge callbacks — optional onFocus / onBlur fire only on the subtree's false ↔ true transitions, never on inner focus moves; kept stable via a latest-ref so new inline handlers never re-subscribe listeners
  • Callback ref — listeners attach/detach exactly when the element mounts, unmounts, or the ref moves to another element (works on React 18 and 19)
  • SSR-safe — no window/document access on the server; initial focused is false
  • StrictMode / concurrent-safe — no duplicate listeners, no stuck state on double mount
  • TypeScript-first — full type inference and exported types
  • Tiny & tree-shakeable — published as its own package

Installation

# npm
npm install @usefy/use-focus-within

# yarn
yarn add @usefy/use-focus-within

# pnpm
pnpm add @usefy/use-focus-within

Requires React 18 or 19 (peerDependencies: "react": "^18.0.0 || ^19.0.0").

Quick Start

import { useFocusWithin } from "@usefy/use-focus-within";

function ContactForm() {
  const [ref, focused] = useFocusWithin<HTMLFormElement>();

  return (
    <form
      ref={ref}
      style={{ outline: focused ? "2px solid dodgerblue" : "none" }}
    >
      <input placeholder="Name" />
      <input placeholder="Email" />
      <button type="submit">Send</button>
    </form>
  );
}

API

useFocusWithin(options?)

const [ref, focused] = useFocusWithin<T>(options?);
// <div ref={ref}> …focusable content… </div>

Returns a [ref, focused] tuple:

| Element | Type | Description | | --------- | ----------------------------- | ----------------------------------------------------------------------------------------------- | | ref | (node: T \| null) => void | A stable callback ref to attach to the container element you want to track. | | focused | boolean | true whenever the active element is the container or any descendant. Starts false (also on the server). |

T defaults to HTMLElement; pass the concrete element type (e.g. HTMLFormElement) for a precisely-typed ref.

Options — UseFocusWithinOptions

| Option | Type | Description | | --------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------- | | onFocus | (event: FocusEvent) => void | Fires when focus enters a previously-unfocused subtree. Receives the triggering focusin event. | | onBlur | (event: FocusEvent) => void | Fires when focus leaves the subtree entirely. Receives the triggering focusout event. |

Both callbacks fire only on the edge transitions — moving focus from one descendant to another fires neither.

Also exported

  • isFocusInside(container, target) — the reusable predicate for "is this node the container or a descendant of it" (folds in the null cases).
  • Types: UseFocusWithinOptions, UseFocusWithinRef, UseFocusWithinReturn.

How focusout is resolved

On focusout the hook decides whether focus truly left the subtree:

  1. If event.relatedTarget is a node inside the container → focus just moved between descendants; stay focused.
  2. If relatedTarget is a node outside the container → focus left; go false.
  3. If relatedTarget is null (unreliable — reported when focus goes to nothing, to another window, or by browsers that omit it) → defer one microtask and re-check document.activeElement; go false only if focus genuinely ended up outside.

Step 3 is what makes the hook robust to the well-known null-relatedTarget quirk while staying fully testable in jsdom.

Examples

Highlight a card while it's being filled in

const [ref, focused] = useFocusWithin<HTMLDivElement>();

return (
  <div ref={ref} className={focused ? "card card--active" : "card"}>
    <input placeholder="Card number" />
    <input placeholder="Expiry" />
    <input placeholder="CVC" />
  </div>
);

Run side effects on enter/leave

const [ref, focused] = useFocusWithin<HTMLDivElement>({
  onFocus: () => analytics.track("filter_group_focused"),
  onBlur: () => validateGroup(),
});

onFocus/onBlur fire only on the subtree's transitions — tabbing across the inner fields won't re-fire them.

Reveal a toolbar while a region is active

const [ref, focused] = useFocusWithin<HTMLDivElement>();

return (
  <div ref={ref}>
    <textarea placeholder="Write something…" />
    {focused && <FormattingToolbar />}
  </div>
);

Testing

📊 View Detailed Coverage Report (GitHub Pages) — 26 tests, 98% statement coverage.

  • useFocusWithin.test.tsx — hook behavior (focus in/out, container-level focus, no-flicker between descendants, leave to outside, blur-to-nothing; relatedTarget inside/outside/null- and undefined-quirk branches; onFocus/onBlur edge semantics; latest-callback without re-subscribe; callback-ref attach/detach, initial-focus sync, detach reset, unmount cleanup; ref stability, SSR-inert default, StrictMode) plus the isFocusInside predicate in isolation.

License

MIT © mirunamu

This package is part of the usefy monorepo.