# FocusTrap `focustrap` is a **focus-management behavior primitive**. While it's `active`, it traps keyboard focus inside its content: Tab and Shift+Tab cycle through the focusable elements *within* the region instead of leaving it. It's the focus behavior that powers modals and drawers, so a keyboard user can't tab "behind" an open dialog. It renders **no visual chrome of its own**. The trapped child supplies the panel, form, or overlay you want readers to see. Use it as `{% focustrap %}` in Markdown, or call it from Python logic (loops, snippets) via `component('aardvark', 'focustrap', …)`. Close the block with `{% endFocustrap %}` (one capital F). ## Demonstrations Activate the demo, then press Tab. Focus moves into the trap and cycles through the field and buttons until you release it. With the trap off, Tab can reach the outside control.
Wrap a region whose focusable elements should be trapped; the block body is that region. In a real modal, mount the trap only while the overlay is open, or pass an `active` value from a stateful island:
third
Set `active=false` to keep the region rendered while the focus trap is disengaged.
Source: Live demo ```aardvark {% FocusTrapDemo %} ``` Source: Markdown ```aardvark {% focustrap %}
third
{% endFocustrap %} ``` Source: Python ```python region = ( '
' '' '' 'third' '
' ) component('aardvark', 'focustrap', children=region) ``` Use `active=false` to disable the trap without removing it. This is useful when a parent owns the open/closed state and only wants focus captured some of the time:
Source: Markdown ```aardvark {% focustrap active=false %}
{% endFocustrap %} ``` Source: Python ```python component( 'aardvark', 'focustrap', active=False, children='
', ) ``` ## With other components A trap wraps the focusable region of a custom overlay you build — for example the body of a `paper` panel acting as a dialog. This rendered example is disengaged so it does not capture page focus while you read:

Source: Markdown ```aardvark {% paper withBorder=true shadow='md' radius='md' p='lg' %} {% focustrap %}
{% endFocustrap %} {% endPaper %} ``` Source: Python ```python form = component( 'aardvark', 'focustrap', children='
' '
', ) component('aardvark', 'paper', withBorder=True, shadow='md', radius='md', p='lg', children=form) ``` ## Attributes | Attribute | Valid values | Description | | --- | --- | --- | | `active` | bare flag or `true` / `false` (default `true`) | Whether the trap is engaged. Set `active=false` to disable it without removing it. | `attr={...}` forwards raw HTML attributes onto the rendered element. ## CSS Selectors Target FocusTrap from your own CSS with the island data attribute. FocusTrap is a behavior wrapper, so it renders no Mantine part classes of its own: ```css /* Every FocusTrap instance on the page */ [data-aardvark-island="FocusTrap"] { } /* FocusTrap is a behavior wrapper — it renders no .mantine-FocusTrap-* parts, forwarding its markup through unchanged. Style its data attribute instead. */ ``` ## Injecting Attributes Pass `attr={…}` to forward raw HTML attributes — including inline event handlers — onto the trapped element. FocusTrap is not itself a value input, so this example makes a `nativeselect` the trapped child and attaches `onchange` to that input. Choose an option: the handler reads the selected value, writes it back into the demo, logs it, and alerts it.
Choose an option.

Source: Markdown ```aardvark
{% focustrap active=false attr={'onchange': ''' const value = event.target.value || ''; const root = event.target.closest('[data-focustrap-attr-demo]'); const output = root ? root.querySelector('[data-focustrap-output]') : null; if (output) output.textContent = value ? 'Last value: ' + value : 'No value entered'; console.log('focustrap attr value:', value); alert(value); '''} %} {% nativeselect label='Framework' data='React|Vue|Svelte|Angular' %} {% endFocustrap %} Choose an option.
``` Source: Python ```python handler = ''' const value = event.target.value || ''; const root = event.target.closest('[data-focustrap-attr-demo]'); const output = root ? root.querySelector('[data-focustrap-output]') : null; if (output) output.textContent = value ? 'Last value: ' + value : 'No value entered'; console.log('focustrap attr value:', value); alert(value); ''' field = component( 'aardvark', 'focustrap', active=False, children=component('aardvark', 'nativeselect', label='Framework', data='React|Vue|Svelte|Angular'), attr={'onchange': handler}, ) page.print( '
' + field + 'Choose an option.' + '
' ) ```