Utilities
Focus trap

Focus Trap

Trap focus within a specified container.

Motivation

Focus trapping is essential for modal interfaces and other interactive elements that require user attention.

The FocusTrap component helps maintain accessibility by ensuring keyboard focus remains within a designated container until explicitly released.

Examples

import { FocusTrap } from "@ark-ui/react/focus-trap";
import { useState } from "react";

export const Basic = () => {
	const [trapped, setTrapped] = useState(false);
	return (
		<>
			<button onClick={() => setTrapped(true)}>Start Trap</button>
			<FocusTrap returnFocusOnDeactivate={false} disabled={!trapped}>
				<div
					style={{
						display: "flex",
						flexDirection: "column",
						gap: "1rem",
						paddingBlock: "1rem",
					}}
				>
					<input type="text" placeholder="input" />
					<textarea placeholder="textarea" />
					<button onClick={() => setTrapped(false)}>End Trap</button>
				</div>
			</FocusTrap>
		</>
	);
};

Autofocus

The focus trap respects elements with the autofocus attribute.

import { FocusTrap } from "@ark-ui/react/focus-trap";
import { useRef, useState } from "react";

export const Autofocus = () => {
	const [trapped, setTrapped] = useState(false);
	const toggle = () => setTrapped((c) => !c);

	const buttonRef = useRef<HTMLButtonElement | null>(null);
	const getButtonNode = () => {
		const node = buttonRef.current;
		if (!node) throw new Error("Button not found");
		return node;
	};

	return (
		<div>
			<button ref={buttonRef} onClick={toggle}>
				{trapped ? "End Trap" : "Start Trap"}
			</button>
			{trapped && (
				<FocusTrap disabled={!trapped} setReturnFocus={getButtonNode}>
					<div
						style={{
							display: "flex",
							flexDirection: "column",
							gap: "1rem",
							paddingBlock: "1rem",
						}}
					>
						<input type="text" placeholder="Regular input" />
						{/* biome-ignore lint/a11y/noAutofocus: <explanation> */}
						<input type="text" placeholder="Autofocused input" autoFocus />
						<button onClick={() => setTrapped(false)}>End Trap</button>
					</div>
				</FocusTrap>
			)}
		</div>
	);
};

Initial Focus

Use the initialFocus prop to set the element that should receive initial focus when the trap is activated.

import { FocusTrap } from "@ark-ui/react/focus-trap";
import { useRef, useState } from "react";

export const InitialFocus = () => {
	const [trapped, setTrapped] = useState(false);
	const toggle = () => setTrapped((c) => !c);

	const inputRef = useRef<HTMLInputElement>(null);

	return (
		<div>
			<button onClick={toggle}>{trapped ? "End Trap" : "Start Trap"}</button>
			<FocusTrap disabled={!trapped} initialFocus={() => inputRef.current}>
				<div
					style={{
						display: "flex",
						flexDirection: "column",
						gap: "1rem",
						paddingBlock: "1rem",
					}}
				>
					<input type="text" placeholder="First input" />
					<input
						ref={inputRef}
						type="text"
						placeholder="Second input (initial focus)"
					/>
					<textarea placeholder="textarea" />
					<button onClick={() => setTrapped(false)}>End Trap</button>
				</div>
			</FocusTrap>
		</div>
	);
};

API Reference