Keeps a marquee clone's interactive elements clickable while removing them from keyboard tab order and the accessibility tree — solving the "clone cards swallow clicks" bug caused by using `inert`.
## Key Components
**`CLONE_FOCUSABLE_SELECTOR`** — Comprehensive CSS selector covering all natively focusable elements: anchors, form controls, `iframe`, `summary`, media with `controls`, `[tabindex]`, and editable content regions.
**`useSuppressCloneFocus(active: boolean)`** — React hook that returns a `ref` to attach to a clone wrapper `
`. When `active`, it:
- Sets `tabindex="-1"` on every focusable descendant (removes duplicate tab stops)
- Watches for DOM mutations that could re-introduce tabbable elements via `MutationObserver`
- Leaves click/pointer behavior fully intact (unlike `inert`, which blocks all interaction)
- Re-applies suppression only when `tabindex` hasn't already been stamped, preventing infinite observer loops
## Usage Example
```typescript
import { useSuppressCloneFocus } from './use-suppress-clone-focus'
function MarqueeClone({ isClone }: { isClone: boolean }) {
const cloneRef = useSuppressCloneFocus(isClone)
return (
// aria-hidden keeps clone out of a11y tree;
// hook keeps it out of tab order while staying clickable
)
}
```
## Accessibility Contract
| Mechanism | Handled by |
|---|---|
| Out of a11y tree | `aria-hidden` on clone wrapper (caller's responsibility) |
| Out of tab order | This hook (`tabindex="-1"` on all focusable descendants) |
| Clickable / pointer events | Preserved — clone anchors handle mouse,
⌘-click, middle-click, and context menu natively |
> **Why not `inert`?** The `inert` attribute also disables pointer events, causing clone cards near the seam of an endless-loop scroll to silently swallow all clicks — the core bug this hook is designed to prevent.