# useFocusWithin

Whether focus is on the element or anything inside it, like CSS `:focus-within`, with callbacks when focus enters or leaves. Moving focus between children inside doesn't count as leaving.

Switching to another window or tab doesn't count either: focus is still there when the user comes back. Content in a React portal is outside in the DOM, so focus moving into it counts as leaving: put the ref on an element that contains the portal's target too.

## Import

```ts
import { useFocusWithin } from '@vincent.ri/react-tils'
// or only this hook
import { useFocusWithin } from '@vincent.ri/react-tils/useFocusWithin'
```

## Usage

```ts
const [open, setOpen] = useState(false)
const outsideRef = useClickOutside(() => setOpen(false), open)
const [focusRef] = useFocusWithin({ onLeave: () => setOpen(false) })
const ref = useMergedRefs(outsideRef, focusRef)
return (
  <div ref={ref}>
    <button onClick={() => setOpen(!open)}>Menu</button>
    {open && <ul>…</ul>}
  </div>
)
```

## When to use it

Closing a menu, popover, or combobox list when keyboard users Tab out of it, which `useClickOutside` alone misses; saving or collapsing an inline editor when focus leaves it; showing toolbar actions while a composer is focused.

## When not to

Only styling; use CSS `:focus-within`. For a modal, keep focus inside with `useFocusTrap` instead. On iOS, tapping a button doesn't focus it, so pair this with `useClickOutside` for pointer users.

## API

```ts
function useFocusWithin<T extends Element = HTMLElement>(options?: FocusWithinOptions): [(element: T | null) => void, boolean]
```

| Parameter | Description |
| --- | --- |
| `options` | `onEnter`, `onLeave`. Optional; can change every render. |

**Returns** `[ref, focused]`.

### Types

```ts
export type FocusWithinOptions = {
  /** Focus moved into the element from outside. */
  onEnter?: () => void;
  /** Focus left the element and everything in it: Tab past the end, Shift+Tab, or a click elsewhere. */
  onLeave?: () => void;
};
```

## Browser support

Works in all modern browsers.

## Coming from another library?

Other libraries call this `useFocusWithin` (react-aria, Mantine), `useFocusOutside`.

---

266 B minified and brotlied
Source: https://github.com/vincentri/react-tils/blob/main/src/useFocusWithin.ts
Docs page: https://vincentri.github.io/react-tils/hooks/useFocusWithin/
Previous: [useFocusTrap](https://vincentri.github.io/react-tils/hooks/useFocusTrap.md)
Next: [useAutosizeTextarea](https://vincentri.github.io/react-tils/hooks/useAutosizeTextarea.md)
