useFocusWithin
EditTracks whether focus is on an element or one of its descendants.
import { useCallback, useEffect, useState } from "react";
import type { RefCallback } from "react";
export interface UseFocusWithinReturn<ElementType extends HTMLElement> { isFocusWithin: boolean; ref: RefCallback<ElementType>;}
/** Tracks whether focus is on an element or one of its descendants. */export const useFocusWithin = < ElementType extends HTMLElement = HTMLElement,>( enabled: boolean = true,): UseFocusWithinReturn<ElementType> => { const [node, setNode] = useState<ElementType | null>(null); const [isFocusWithin, setIsFocusWithin] = useState(false); const ref = useCallback<RefCallback<ElementType>>((nextNode) => { setNode(nextNode); setIsFocusWithin(false); }, []);
useEffect(() => { if (!enabled || node === null) { setIsFocusWithin(false); return; } setIsFocusWithin(node.contains(node.ownerDocument.activeElement)); const focusIn = () => setIsFocusWithin(true); const focusOut = (event: FocusEvent) => { if (!(event.relatedTarget instanceof Node) || !node.contains(event.relatedTarget)) { setIsFocusWithin(false); } }; node.addEventListener("focusin", focusIn); node.addEventListener("focusout", focusOut); return () => { node.removeEventListener("focusin", focusIn); node.removeEventListener("focusout", focusOut); }; }, [enabled, node]);
return { isFocusWithin, ref };};Download
Section titled “Download”wget -O src/hooks/useFocusWithin.ts https://raw.githubusercontent.com/jrTilak/lazykit/HEAD/registry/react-hooks/useFocusWithin.tstemp_dir="$(mktemp -d)" && bunx degit jrTilak/lazykit/registry/react-hooks "$temp_dir" && mv "$temp_dir/useFocusWithin.ts" src/hooks/useFocusWithin.ts && rm -r "$temp_dir"Examples
Section titled “Examples”import { useFocusWithin } from "./useFocusWithin";
export const FocusWithinExample = () => { const { ref, isFocusWithin } = useFocusWithin<HTMLFieldSetElement>();
return ( <fieldset ref={ref}> <legend>{isFocusWithin ? "Editing" : "Contact"}</legend> <input aria-label="Email" type="email" /> <button type="button">Save</button> </fieldset> );};enabled(boolean) — Enables focus listeners. Defaults totrue.ElementType— Generic HTML element type attached to the callback ref.
Returns
Section titled “Returns”UseFocusWithinReturn<ElementType> with ref and isFocusWithin.