44![ JavaScript] ( https://img.shields.io/badge/language-JavaScript-F7DF1E?logo=javascript )
55[ ![ npm version] ( https://img.shields.io/npm/v/%40rethink-js%2Frt-smooth-scroll.svg )] ( https://www.npmjs.com/package/@rethink-js/rt-smooth-scroll )
66[ ![ jsDelivr hits] ( https://data.jsdelivr.com/v1/package/npm/@rethink-js/rt-smooth-scroll/badge )] ( https://www.jsdelivr.com/package/npm/@rethink-js/rt-smooth-scroll )
7- [ ![ bundle size] ( https://img.shields.io/bundlephobia/min/%40rethink-js%2Frt-smooth-scroll )] ( https://bundlephobia.com/package/@rethink-js/rt-smooth-scroll )
87[ ![ License: MIT] ( https://img.shields.io/badge/License-MIT-FFD632.svg )] ( https://opensource.org/licenses/MIT )
98
109` rt-smooth-scroll ` is a lightweight JavaScript library that seamlessly integrates the ** Lenis smooth scroll engine** into your sites with:
1514- A clean global API under ` window.rtSmoothScroll `
1615- ** Smart Scroll-To actions** with indexed selectors and dynamic offsets
1716- ** Automatic Anchor Link Conversion** (hijack native links for smooth scrolling)
17+ - ** Scroll-To Completion Hooks** (run actions/functions after a scroll-to completes)
1818- Per-instance configuration via HTML attributes
1919- Console logs showing each instance’s final resolved config
2020
4545### 1.1 CDN (jsDelivr)
4646
4747``` html
48- <script src =" [ https://cdn.jsdelivr.net/npm/@rethink-js/rt-smooth-scroll@latest/dist/index.min.js](https://cdn.jsdelivr.net/npm/@rethink-js/rt-smooth-scroll@latest/dist/index.min.js) " ></script >
48+ <script src =" https://cdn.jsdelivr.net/npm/@rethink-js/rt-smooth-scroll@latest/dist/index.min.js" ></script >
4949```
5050
5151### 1.2 npm
@@ -70,7 +70,7 @@ Add the script to your page. With no configuration provided, `rt-smooth-scroll`
7070Example:
7171
7272``` html
73- <script src =" [ https://cdn.jsdelivr.net/npm/@rethink-js/rt-smooth-scroll@latest/dist/index.min.js](https://cdn.jsdelivr.net/npm/@rethink-js/rt-smooth-scroll@latest/dist/index.min.js) " ></script >
73+ <script src =" https://cdn.jsdelivr.net/npm/@rethink-js/rt-smooth-scroll@latest/dist/index.min.js" ></script >
7474```
7575
7676> Note: If you do not set any ` rt-smooth-scroll-* ` config attributes, the root instance uses ** Lenis defaults** .
@@ -117,21 +117,27 @@ Important Lenis behavior:
117117
118118** Core attributes:**
119119
120- | Attribute | Description |
121- | ------------------------------------------- | ------------------------------------------------------------ |
122- | ` rt-smooth-scroll-duration ` | Lenis ` duration ` (only applies when ` lerp ` is not used) |
123- | ` rt-smooth-scroll-lerp ` | Lenis ` lerp ` (0 → 1) |
124- | ` rt-smooth-scroll-orientation ` | Lenis ` orientation ` |
125- | ` rt-smooth-scroll-gesture-orientation ` | Lenis ` gestureOrientation ` |
126- | ` rt-smooth-scroll-normalize-wheel ` | Lenis ` normalizeWheel ` |
127- | ` rt-smooth-scroll-wheel-multiplier ` | Lenis ` wheelMultiplier ` |
128- | ` rt-smooth-scroll-smooth-touch ` | Lenis ` smoothTouch ` |
129- | ` rt-smooth-scroll-sync-touch ` | Lenis ` syncTouch ` |
130- | ` rt-smooth-scroll-sync-touch-lerp ` | Lenis ` syncTouchLerp ` |
131- | ` rt-smooth-scroll-touch-inertia-multiplier ` | Lenis ` touchInertiaMultiplier ` |
132- | ` rt-smooth-scroll-touch-multiplier ` | Lenis ` touchMultiplier ` |
133- | ` rt-smooth-scroll-infinite ` | Lenis ` infinite ` |
134- | ` rt-smooth-scroll-easing ` | Named easing function (only applies when ` lerp ` is not used) |
120+ | Attribute | Description |
121+ | ----------------------------------------- | ------------------------------------------------------------ |
122+ | ` rt-smooth-scroll-duration ` | Lenis ` duration ` (only applies when ` lerp ` is not used) |
123+ | ` rt-smooth-scroll-lerp ` | Lenis ` lerp ` (0 → 1) |
124+ | ` rt-smooth-scroll-orientation ` | Lenis ` orientation ` |
125+ | ` rt-smooth-scroll-gesture-orientation ` | Lenis ` gestureOrientation ` |
126+ | ` rt-smooth-scroll-normalize-wheel ` | Alias of Lenis ` smoothWheel ` (legacy naming supported) |
127+ | ` rt-smooth-scroll-smooth-wheel ` | Lenis ` smoothWheel ` |
128+ | ` rt-smooth-scroll-wheel-multiplier ` | Lenis ` wheelMultiplier ` |
129+ | ` rt-smooth-scroll-touch-multiplier ` | Lenis ` touchMultiplier ` |
130+ | ` rt-smooth-scroll-sync-touch ` | Lenis ` syncTouch ` |
131+ | ` rt-smooth-scroll-sync-touch-lerp ` | Lenis ` syncTouchLerp ` |
132+ | ` rt-smooth-scroll-touch-inertia-exponent ` | Lenis ` touchInertiaExponent ` |
133+ | ` rt-smooth-scroll-infinite ` | Lenis ` infinite ` |
134+ | ` rt-smooth-scroll-auto-resize ` | Lenis ` autoResize ` |
135+ | ` rt-smooth-scroll-overscroll ` | Lenis ` overscroll ` |
136+ | ` rt-smooth-scroll-anchors ` | Lenis ` anchors ` (boolean or JSON) |
137+ | ` rt-smooth-scroll-auto-toggle ` | Lenis ` autoToggle ` |
138+ | ` rt-smooth-scroll-allow-nested-scroll ` | Lenis ` allowNestedScroll ` |
139+ | ` rt-smooth-scroll-easing ` | Named easing function (only applies when ` lerp ` is not used) |
140+ | ` rt-smooth-scroll-options-json ` | Merge additional Lenis options via JSON |
135141
136142** Easing options included:**
137143
@@ -164,6 +170,31 @@ Add attributes to any scroll container:
164170| ` rt-smooth-scroll-id ` | Optional instance identifier |
165171| ` rt-smooth-scroll-content ` | Selector inside container (defaults to first child if omitted) |
166172
173+ ### Advanced Selectors (wrapper/content/eventsTarget)
174+
175+ You can map Lenis DOM targets using selectors:
176+
177+ ``` html
178+ <body
179+ rt-smooth-scroll
180+ rt-smooth-scroll-wrapper =" #page-wrapper"
181+ rt-smooth-scroll-content =" #page-content"
182+ rt-smooth-scroll-events-target =" #page-wrapper"
183+ ></body >
184+ ```
185+
186+ Or per instance:
187+
188+ ``` html
189+ <div
190+ rt-smooth-scroll-instance
191+ rt-smooth-scroll-id =" panel"
192+ rt-smooth-scroll-wrapper =" #panel-wrapper"
193+ rt-smooth-scroll-content =" .panel-content"
194+ rt-smooth-scroll-events-target =" #panel-wrapper"
195+ ></div >
196+ ```
197+
167198---
168199
169200## 5. Scroll-To Actions
@@ -211,6 +242,126 @@ Instead of hardcoding pixels, you can pass a selector to `rt-smooth-scroll-offse
211242</button >
212243```
213244
245+ ### Scroll-To Completion Hooks
246+
247+ When a scroll-to finishes (including the built-in correction pass for layout shifts), you can run an action/function.
248+
249+ ** Supported hook attributes:**
250+
251+ - Per-trigger: ` rt-smooth-scroll-on-complete `
252+ - Global default: ` rt-smooth-scroll-on-complete ` on ` <html> ` or ` <body> `
253+
254+ #### 5.1 Per-trigger completion action
255+
256+ Click an element after the scroll completes:
257+
258+ ``` html
259+ <a rt-smooth-scroll-to =" #contact" rt-smooth-scroll-on-complete =" #nav-show" >
260+ Contact
261+ </a >
262+ ```
263+
264+ The shorthand above treats the value as a selector and will ` click() ` it.
265+
266+ You can also be explicit:
267+
268+ ``` html
269+ <a
270+ rt-smooth-scroll-to =" #contact"
271+ rt-smooth-scroll-on-complete =" click:#nav-show"
272+ >
273+ Contact
274+ </a >
275+ ```
276+
277+ #### 5.2 Global default completion action
278+
279+ Apply to all scroll-to triggers unless they override it:
280+
281+ ``` html
282+ <body rt-smooth-scroll rt-smooth-scroll-on-complete =" click:#nav-show" ></body >
283+ ```
284+
285+ #### 5.3 Supported completion action formats
286+
287+ ** 1) Selector-only (defaults to click)**
288+
289+ ``` html
290+ <button rt-smooth-scroll-to =" #x" rt-smooth-scroll-on-complete =" #nav-show" >
291+ Go
292+ </button >
293+ ```
294+
295+ ** 2) Typed strings**
296+
297+ - ` click:#selector `
298+ - ` focus:#selector `
299+ - ` dispatch:event-name ` (fires ` CustomEvent ` on ` window ` )
300+ - ` call:functionName ` (calls ` window[functionName] ` )
301+
302+ Examples:
303+
304+ ``` html
305+ <button rt-smooth-scroll-to =" #x" rt-smooth-scroll-on-complete =" focus:#search" >
306+ Go
307+ </button >
308+
309+ <button
310+ rt-smooth-scroll-to =" #x"
311+ rt-smooth-scroll-on-complete =" dispatch:rt:smooth-scroll:complete"
312+ >
313+ Go
314+ </button >
315+
316+ <button
317+ rt-smooth-scroll-to =" #x"
318+ rt-smooth-scroll-on-complete =" call:afterScroll"
319+ >
320+ Go
321+ </button >
322+ ```
323+
324+ When using ` call:functionName ` , your function receives a single object:
325+
326+ ``` js
327+ window .afterScroll = function (ctx ) {
328+ console .log (" afterScroll" , ctx);
329+ };
330+ ```
331+
332+ ` ctx ` includes:
333+
334+ - ` lenis ` (the Lenis instance used)
335+ - ` trigger ` (the element that initiated the scroll)
336+ - ` target ` (resolved target number/element/window)
337+ - ` value ` (the raw ` rt-smooth-scroll-to ` string)
338+ - ` id ` (the explicit ` rt-smooth-scroll-target-id ` if provided)
339+
340+ ** 3) JSON actions (single or array)**
341+
342+ This is the most robust option for multi-step actions:
343+
344+ ``` html
345+ <button
346+ rt-smooth-scroll-to =" #x"
347+ rt-smooth-scroll-on-complete =' [
348+ {"type":"click","selector":"#nav-show"},
349+ {"type":"dispatch","name":"rt:smooth-scroll:complete","detail":{"from":"scroll-to"}}
350+ ]'
351+ >
352+ Go
353+ </button >
354+ ```
355+
356+ Supported JSON action types:
357+
358+ - ` { "type": "click", "selector": "#el" } `
359+ - ` { "type": "focus", "selector": "#el" } `
360+ - ` { "type": "dispatch", "name": "event-name", "detail": any } `
361+ - ` { "type": "call", "name": "functionName", "detail": any } `
362+
363+ For ` dispatch ` and ` call ` , ` detail ` is merged into the context under ` detail ` .
364+
214365---
215366
216367## 6. Anchor Link Conversion
@@ -230,7 +381,24 @@ Add this attribute to your `<body>` or `<html>` tag:
2303811 . ** Auto-Detection:** Finds all links pointing to a hash on the current page.
2313822 . ** Hijacking:** Converts them to use the ` rt-smooth-scroll-to ` logic.
2323833 . ** Clean URLs:** Removes the ` href ` attribute so the browser URL bar does ** not** update (no ` #hash ` in URL), keeping your history clean.
233- 4 . ** Accessibility:** Automatically restores ` tabindex="0" ` , ` role="button" ` , ` cursor: pointer ` , and keyboard ` Enter ` key support.
384+ 4 . ** Accessibility:** Automatically restores ` tabindex="0" ` , ` role="button" ` , ` cursor: pointer ` , and keyboard ` Enter ` / ` Space ` key support.
385+
386+ ### Anchor link completion hook (auto-injected)
387+
388+ You can automatically attach a completion hook to every converted anchor link:
389+
390+ ``` html
391+ <body
392+ rt-smooth-scroll
393+ rt-smooth-scroll-anchor-links =" true"
394+ rt-smooth-scroll-anchor-links-on-complete =" click:#nav-show"
395+ ></body >
396+ ```
397+
398+ Rules:
399+
400+ - If a link already has ` rt-smooth-scroll-on-complete ` , it is not overridden.
401+ - If ` rt-smooth-scroll-anchor-links-on-complete ` exists, it is copied into each converted link as ` rt-smooth-scroll-on-complete ` .
234402
235403---
236404
@@ -297,18 +465,23 @@ This helps you confirm exactly what configuration is applied in the browser.
297465
298466Lenis treats ` duration ` and ` easing ` as ** useless if ` lerp ` is defined** . If you want time-based behavior, ensure you’re not effectively running in lerp-mode.
299467
468+ ### My ` rt-smooth-scroll-on-complete ` didn’t run
469+
470+ Common causes:
471+
472+ - The selector/function name is wrong or not available at runtime.
473+ - Your completion hook depends on DOM that’s not yet mounted/visible.
474+ - If you are using ` call:fnName ` , ensure ` window.fnName ` exists before the scroll completes.
475+ - If you are using JSON, ensure it is valid JSON (double quotes, no trailing commas).
476+
300477---
301478
302479## 11. License
303480
304481MIT License
305482
306- Package: ` @rethink-js/rt-smooth-scroll `
307- <br >
483+ Package: ` @rethink-js/rt-smooth-scroll ` <br >
308484GitHub: [ https://github.com/Rethink-JS/rt-smooth-scroll ] ( https://github.com/Rethink-JS/rt-smooth-scroll )
309485
310- ---
311-
312- by ** Rethink JS**
313- <br >
486+ by ** Rethink JS** <br >
314487[ https://github.com/Rethink-JS ] ( https://github.com/Rethink-JS )
0 commit comments