Components / Focus Scope
Focus Scope
Headless focus-trap primitive. Cycles Tab/Shift+Tab within its children when active, and (optionally) returns focus to the previously-focused element on deactivate. Renders no chrome — uses display:contents — so wrap with cg-card / cg-stack / your own surface to make it visible.
layout v0.8.0
Playground
Examples
Active trap inside a card
<cg-card padding="lg">
<cg-focus-scope active>
<cg-stack direction="column" gap="md">
<cg-text size="sm" muted>Tab cycles between these three buttons. Try it.</cg-text>
<cg-stack direction="row" gap="sm">
<cg-button variant="primary">Save</cg-button>
<cg-button variant="secondary">Cancel</cg-button>
<cg-button variant="tertiary">Help</cg-button>
</cg-stack>
</cg-stack>
</cg-focus-scope>
</cg-card> Inactive (Tab leaves freely)
<cg-card padding="lg">
<cg-focus-scope>
<cg-stack direction="column" gap="md">
<cg-text size="sm" muted>Trap is inactive — Tab will move past the last button and on to the rest of the page.</cg-text>
<cg-stack direction="row" gap="sm">
<cg-button variant="secondary">First</cg-button>
<cg-button variant="secondary">Second</cg-button>
</cg-stack>
</cg-stack>
</cg-focus-scope>
</cg-card> Form trap (modal pattern)
<cg-card padding="lg">
<cg-focus-scope active>
<cg-stack direction="column" gap="md">
<cg-text size="md" weight="semibold">Confirm delete</cg-text>
<cg-input label="Type DELETE to confirm" placeholder="DELETE"></cg-input>
<cg-stack direction="row" gap="sm" justify="end">
<cg-button variant="tertiary">Cancel</cg-button>
<cg-button variant="primary" type="danger">Delete</cg-button>
</cg-stack>
</cg-stack>
</cg-focus-scope>
</cg-card> Import
import { CgFocusScope } from '@cognivo/components'; // Or tree-shake: import '@cognivo/components/cg-focus-scope'; Per-component imports ship only that component (~8 kB gzip).
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
active | boolean | false | Trap is active |
returnFocus | boolean | true | Restore previous focus on deactivate |