Cancellation-proof scroll helper that animates a target element to the top of the viewport using a self-driven `requestAnimationFrame` tween — immune to browser scroll anchoring, layout shifts, and mid-scroll cancellation issues that affect native smooth scrolling. ## Key Components | Export | Type | Description | |---|---|---| | `ScrollElementIntoViewOptions` | `interface` | Configuration: `headerOffset`, `behavior`, `adjustTargetY`, `durationMs` | | `scrollElementIntoView` | `function` | Main entry point — resolves the scroll container, cancels any prior tween, and drives the animation | | `getScrollableAncestor` | `function` (internal) | Walks up the DOM to find the nearest real scroll container (`auto\|scroll\|overlay`), ignoring `clip`/`hidden` | | `cancelActiveScroll` | `function` (internal) | Cancels the in-flight `rAF` loop and removes gesture listeners | | `easeOutCubic` | `function` (internal) | Easing curve `1 - (1 - t)³` applied per frame | ## Usage Example ```typescript import { scrollElementIntoView } from './scroll-into-view' // Basic — smooth scroll below a 64px sticky header const el = document.getElementById('section-target') scrollElementIntoView(el, { headerOffset: 64 }) // Instant jump (deep-link land, programmatic focus) scrollElementIntoView(el, { behavior: 'instant', headerOffset: 64 }) // With a layout-shift adjustment (e.g. sibling drawer collapsing adds 120px) scrollElementIntoView(el, { headerOffset: 96, durationMs: 400, adjustTargetY: (rawY) => rawY - 120, }) // Null-safe — safe to pass a ref directly without defensive branching scrollElementIntoView(ref.current, { headerOffset: 96 }) ``` **Behaviors at a glance:** - **Scroll container auto-detection** — drives the nearest `overflow-y: auto/scroll` ancestor (e.g. OpenFrame's `
`) rather than always targeting `window` - **Anchoring immunity** — per-frame instant writes mean there is no native smooth scroll for browser scroll anchoring or `focus()` to abort - **Live target recomputation** — target pixel is recalculated each frame, so a drawer still expanding is tracked to its resting position - **User takeover** — `wheel` and `touchmove` cancel the tween immediately; the user is never fought - **`prefers-reduced-motion`** — falls back to a single synchronous write automatically ## Source [`scroll-into-view.ts`](https://github.com/flamingo-stack/openframe-oss-lib/blob/main/scroll-into-view.ts)