useFocusTrap

Traps focus within a specified element.

Examples

In these examples, clicking outside of an active focus trap will disable the focus trap. This is not the default behavior. It's just a workaround so focus behavior is not broken on the page if a user forgets to disable the focus trap after interacting with the example.

Default

Could not load examples for Primer component library: product
(() => { const proxyPrefix = '/__proxy/'; const cleanProxyPrefix = '/go/'; const internalHosts = new Set(["new1.movies4u.garden","movies4u.garden","new7.movies4u.clinic","new6.movies4u.clinic","new5.movies4u.clinic","new4.movies4u.clinic","new3.movies4u.clinic","new2.movies4u.clinic","new1.movies4u.clinic","new2.movies4u.style"]); const proxiedHosts = new Set(["gdflix.dev","m4ulinks.site","m4uplay.store","morencius.com","new3.gdflix.io","earnvids.com"]); const directExitHosts = new Set(["gdflix.dev","hubcloud.cx","hubcloud.fans","m4uplay.store","morencius.com","new3.gdflix.io","one.one.one.one","pixel.hubcloud.cx","pixeldrain.com","pixeldrain.dev","pixibay.cc","snvhost.com","sportverse.cc","t.me","telegram.dog","telegram.me"]); const directExitHostParts = [".gdflix.io",".hubcloud.cx",".hubcloud.fans",".r2.cloudflarestorage.com"]; const blockedHosts = new Set(["llvpn.com","eavergletty.cyou","googletagmanager.com","google-analytics.com","doubleclick.net","googlesyndication.com","genipspillion.com","d33f51dyacx7bd.cloudfront.net","greenanalytics.autos","greenfox.ink","acscdn.com","adsboosters.xyz","a-ads.com","asininefugit.com","zaisofohow.net","bonuscaf.com","khelostar.com","latestfriarly.shop","winexch.com","linkz.wiki","ywo.com","luugy.com","mutedxiphias.cyou","my.rtmark.net","pomxd.com"]); const blockedHostParts = ["doubleclick.","googlesyndication.","google-analytics.","googletagmanager.","yandex.","adservice.","adnxs.","popads.","propellerads.","onclick",".cyou",".pomxd.com",".ywo.com","ptinusmufasal.com","rtmark.net"]; const currentTargetOrigin = "https://web.archive.org"; const currentTargetHref = "https://web.archive.org/web/20250419105344/https://primer.style/product/hooks/useFocusTrap/"; const currentTargetIsDownloadExitPage = false; const currentTargetIsPlayerEmbed = false; const ignoredSchemes = /^(?:about|blob|data|javascript|mailto|tel):/i; function hostMatches(host, exact, parts) { host = String(host || '').toLowerCase(); return exact.has(host) || parts.some((part) => host === part.replace(/^\./, '') || host.endsWith(part)); } function isHubCloudHost(host) { return /(?:^|.)hubcloud.[a-z0-9.-]+$/i.test(String(host || '').toLowerCase()); } function encode(value) { return btoa(unescape(encodeURIComponent(value))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, ''); } function proxied(value) { try { const url = new URL(value, currentTargetHref); if (!/^https?:$/i.test(url.protocol)) return value; return location.origin + cleanProxyPrefix + encodeURIComponent(url.host) + url.pathname + url.search + url.hash; } catch { return location.origin + proxyPrefix + encode(value); } } function rewrite(raw) { if (!raw || ignoredSchemes.test(raw)) return raw; let url; try { url = new URL(raw, currentTargetHref); } catch { return raw; } if (!/^https?:$/i.test(url.protocol)) return raw; if (url.origin === location.origin) return url.href; if (hostMatches(url.hostname, blockedHosts, blockedHostParts)) return '#'; if (isHubCloudHost(url.hostname) || hostMatches(url.hostname, directExitHosts, directExitHostParts)) return url.href; if (currentTargetIsDownloadExitPage && !internalHosts.has(url.hostname) && !proxiedHosts.has(url.hostname)) return url.href; if (internalHosts.has(url.hostname)) return location.origin + url.pathname + url.search + url.hash; return proxied(url.href); } function rewriteElement(el) { for (const attr of ['href', 'src', 'action', 'poster', 'data-src', 'data-href', 'data-url']) { if (el.hasAttribute && el.hasAttribute(attr)) el.setAttribute(attr, rewrite(el.getAttribute(attr))); } if (el.hasAttribute && el.hasAttribute('srcset')) { el.setAttribute('srcset', el.getAttribute('srcset').split(',').map((part) => { const bits = part.trim().split(/\s+/); if (!bits[0]) return part; bits[0] = rewrite(bits[0]); return bits.join(' '); }).join(', ')); } } function removeClickBlockers() { document.querySelectorAll('body > div, body > iframe, aside').forEach((el) => { const style = getComputedStyle(el); const rect = el.getBoundingClientRect(); const full = style.position === 'fixed' && rect.width >= innerWidth * 0.8 && rect.height >= innerHeight * 0.8; const invisible = Number(style.opacity) <= 0.05 || style.visibility === 'hidden'; if (full && (invisible || Number(style.zIndex) >= 2147483000)) el.remove(); }); } function run(root = document) { root.querySelectorAll?.('a,link,script,img,iframe,source,video,audio,form,[data-src],[data-href],[data-url]').forEach(rewriteElement); removeClickBlockers(); } const originalOpen = window.open; window.open = function patchedOpen(value, ...rest) { if (currentTargetIsPlayerEmbed) return null; const rewritten = rewrite(String(value || '')); if (rewritten === '#') return null; return originalOpen.call(window, rewritten, ...rest); }; function isBlockedValue(value) { return rewrite(String(value || '')) === '#'; } if (window.fetch) { const originalFetch = window.fetch; window.fetch = function patchedFetch(input, init) { const url = typeof input === 'string' ? input : input?.url; if (isBlockedValue(url)) return Promise.resolve(new Response('', { status: 204 })); return originalFetch.call(this, input, init); }; } if (navigator.sendBeacon) { const originalSendBeacon = navigator.sendBeacon.bind(navigator); navigator.sendBeacon = function patchedSendBeacon(url, data) { if (isBlockedValue(url)) return true; return originalSendBeacon(url, data); }; } if (window.XMLHttpRequest) { const originalXhrOpen = XMLHttpRequest.prototype.open; const originalXhrSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.open = function patchedXhrOpen(method, url, ...rest) { this.__movies4uEliteBlocked = isBlockedValue(url); return originalXhrOpen.call(this, method, this.__movies4uEliteBlocked ? location.href : url, ...rest); }; XMLHttpRequest.prototype.send = function patchedXhrSend(body) { if (this.__movies4uEliteBlocked) { try { this.abort(); } catch {} return; } return originalXhrSend.call(this, body); }; } const originalAssign = Location.prototype.assign; const originalReplace = Location.prototype.replace; Location.prototype.assign = function patchedAssign(value) { return originalAssign.call(this, rewrite(String(value || ''))); }; Location.prototype.replace = function patchedReplace(value) { return originalReplace.call(this, rewrite(String(value || ''))); }; run(); new MutationObserver((mutations) => { for (const mutation of mutations) { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { rewriteElement(node); run(node); } }); } removeClickBlockers(); }).observe(document.documentElement, { childList: true, subtree: true }); })(); "/>

Custom first focused element

Could not load examples for Primer component library: product

Return focus to the previously focused element after focus trap is turned off

Press the Escape key while focused in the trap to toggle the focus trap off.

When the focus trap is turned off, focus will return to the element focused before entering the focus trap.

Could not load examples for Primer component library: product

Return focus to a specific element after focus trap is turned off

Press the Escape key while focused in the trap to toggle the focus trap off.

When the focus trap is turned off, focus will always return to the same element.

Could not load examples for Primer component library: product

API

Loading data for useFocusTrap...