{"id":11465,"library":"normalize-scroll-left","title":"Normalize Scroll Left","description":"This utility library addresses the inconsistent behavior of the `Element.scrollLeft` property when an element's direction is set to Right-to-Left (RTL) across different browsers. It provides methods to detect the browser's specific `scrollLeft` implementation type (e.g., WebKit's 'default', Firefox/Opera's 'negative', IE/Edge's 'reverse') and then normalize `scrollLeft` values to a consistent, WebKit-like `0` (most left) to `100` (most right) range for both getting and setting. The current stable version is 0.2.1. Releases appear to be driven by bug fixes and feature enhancements, such as ESM support in v0.2.0. Its key differentiator is robust feature detection to abstract away browser quirks, enabling developers to work with a predictable `scrollLeft` API for RTL content, based on established patterns from jQuery plugins and Stack Overflow solutions. It explicitly handles Server-Side Rendering (SSR) environments by returning `indeterminate` or `NaN` for relevant functions, indicating non-browser execution.","status":"active","version":"0.2.1","language":"javascript","source_language":"en","source_url":"ssh://git@github.com/alitaheri/normalize-scroll-left","tags":["javascript","rtl","dom","scroll-left","scrollLeft","normalize","browser","element","typescript"],"install":[{"cmd":"npm install normalize-scroll-left","lang":"bash","label":"npm"},{"cmd":"yarn add normalize-scroll-left","lang":"bash","label":"yarn"},{"cmd":"pnpm add normalize-scroll-left","lang":"bash","label":"pnpm"}],"dependencies":[],"imports":[{"note":"ESM-only since v0.2.0. Function requires a DOM environment and caches its result.","wrong":"const detectScrollType = require('normalize-scroll-left').detectScrollType;","symbol":"detectScrollType","correct":"import { detectScrollType } from 'normalize-scroll-left';"},{"note":"ESM-only since v0.2.0. Requires explicit 'direction' and returns NaN in non-browser environments.","wrong":"const getNormalizedScrollLeft = require('normalize-scroll-left').getNormalizedScrollLeft;","symbol":"getNormalizedScrollLeft","correct":"import { getNormalizedScrollLeft } from 'normalize-scroll-left';"},{"note":"ESM-only since v0.2.0. Requires explicit 'direction' and does nothing in non-browser environments.","wrong":"const setNormalizedScrollLeft = require('normalize-scroll-left').setNormalizedScrollLeft;","symbol":"setNormalizedScrollLeft","correct":"import { setNormalizedScrollLeft } from 'normalize-scroll-left';"}],"quickstart":{"code":"import { detectScrollType, getNormalizedScrollLeft, setNormalizedScrollLeft } from 'normalize-scroll-left';\n\n// This quickstart demonstrates how to use normalize-scroll-left to handle\n// inconsistent Element.scrollLeft behavior in RTL layouts across browsers.\n\n// 1. Detect the browser's scroll type (caches result)\n//    Must be called after the DOM body is loaded.\nconst scrollType = detectScrollType();\nconsole.log(`Detected scroll type: ${scrollType}`); // e.g., 'default', 'negative', 'reverse', 'indeterminate' in SSR\n\n// 2. Create a dummy scrollable element for demonstration\nconst container = document.createElement('div');\ncontainer.id = 'my-scrollable-container';\ncontainer.style.direction = 'rtl';\ncontainer.style.width = '100px';\ncontainer.style.overflowX = 'scroll';\ncontainer.style.whiteSpace = 'nowrap';\ncontainer.style.border = '1px solid black';\ncontainer.innerHTML = '<span style=\"display:inline-block; width:200px; height:20px;\">Scrollable Content</span>';\ndocument.body.appendChild(container);\n\n// Simulate scrolling to the most right (normalized to 100)\nsetNormalizedScrollLeft(container, 100, 'rtl');\nconsole.log(`After setting normalized scrollLeft to 100 (most right): ${getNormalizedScrollLeft(container, 'rtl')}`);\n\n// Simulate scrolling to a specific position (normalized to 20)\nsetNormalizedScrollLeft(container, 20, 'rtl');\nconsole.log(`After setting normalized scrollLeft to 20: ${getNormalizedScrollLeft(container, 'rtl')}`);\n\n// Clean up\ndocument.body.removeChild(container);","lang":"typescript","description":"Demonstrates detecting scroll behavior, creating an RTL scrollable element, and using normalized functions to get and set its scroll position consistently across browsers."},"warnings":[{"fix":"Use ESM `import` statements (e.g., `import { name } from 'pkg';`) instead of CommonJS `require()` for newer versions. Ensure your build system is configured to handle ESM modules.","message":"Version 0.2.0 introduced ESM support via the 'module' field. Projects using CommonJS `require()` might need to adjust their import statements or build configurations to properly consume the package, especially if relying on older Node.js versions or specific bundler setups.","severity":"breaking","affected_versions":">=0.2.0"},{"fix":"Ensure `detectScrollType()` is called in a client-side context after the DOM is ready (e.g., within a `DOMContentLoaded` listener). For SSR, check for `typeof document !== 'undefined'` before invocation or account for the `'indeterminate'` return type.","message":"The `detectScrollType()` function requires a browser DOM environment to operate, as it renders a dummy element. It will return `'indeterminate'` in non-browser (e.g., Node.js/SSR) environments and also if called before `document.body` is fully loaded.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Always pass the correct, explicitly known `direction` ('rtl' or 'ltr') corresponding to the element's computed style. Do not rely on the library to infer it.","message":"Both `getNormalizedScrollLeft()` and `setNormalizedScrollLeft()` explicitly require the `direction` ('rtl' or 'ltr') as an argument. This is for performance reasons to avoid expensive `getComputedStyle` calls and potential reflows. Providing an incorrect `direction` might lead to unexpected scroll behavior.","severity":"gotcha","affected_versions":">=0.1.0"},{"fix":"Implement client-side checks for these functions or handle `NaN` as a possible return value for `getNormalizedScrollLeft()` in universal applications. Avoid calling `setNormalizedScrollLeft()` in SSR contexts where DOM manipulation is not possible.","message":"Functions like `getNormalizedScrollLeft()` return `NaN` and `setNormalizedScrollLeft()` does nothing when executed in a non-browser environment (e.g., Node.js for SSR). This is by design to avoid DOM access errors.","severity":"gotcha","affected_versions":">=0.1.0"}],"env_vars":null,"last_verified":"2026-04-19T00:00:00.000Z","next_check":"2026-07-18T00:00:00.000Z","problems":[{"fix":"Wrap DOM-dependent calls in a client-side check, e.g., `if (typeof document !== 'undefined') { /* call function */ }`, or ensure these functions are only executed on the client-side.","cause":"Attempting to call `detectScrollType`, `getNormalizedScrollLeft`, or `setNormalizedScrollLeft` in a Node.js (Server-Side Rendering) environment without a browser emulation layer.","error":"ReferenceError: document is not defined"},{"fix":"Ensure that `detectScrollType()` is called only after the DOM is ready, for instance, within a `DOMContentLoaded` event listener or at the end of the `<body>` in traditional scripts.","cause":"`detectScrollType()` was invoked before the `document.body` was fully loaded or available, preventing it from rendering the necessary dummy element for feature detection.","error":"detectScrollType() returns 'indeterminate' in browser"},{"fix":"Verify that the `direction` argument (e.g., `'rtl'`) explicitly passed to the normalization functions accurately reflects the `getComputedStyle().direction` of the target `HTMLElement`.","cause":"The `direction` argument passed to `getNormalizedScrollLeft()` or `setNormalizedScrollLeft()` does not match the actual computed `direction` of the `HTMLElement`, or the element's `direction` itself is not correctly set to `rtl`.","error":"Scroll position not normalizing correctly for RTL elements."}],"ecosystem":"npm"}