{"id":19451185,"url":"https://github.com/thekashey/react-stroller","last_synced_at":"2025-09-23T15:31:27.467Z","repository":{"id":53701398,"uuid":"134956342","full_name":"theKashey/React-stroller","owner":"theKashey","description":"🚶‍♂️Scroll as you Stroll - the most native custom scrollbars ever made","archived":false,"fork":false,"pushed_at":"2024-02-08T05:46:35.000Z","size":540,"stargazers_count":44,"open_issues_count":3,"forks_count":3,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-01-11T23:47:51.794Z","etag":null,"topics":["react","scroll","scrollbar"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/theKashey.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-05-26T11:41:30.000Z","updated_at":"2024-02-08T19:41:00.000Z","dependencies_parsed_at":"2024-06-19T00:39:19.297Z","dependency_job_id":null,"html_url":"https://github.com/theKashey/React-stroller","commit_stats":null,"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2FReact-stroller","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2FReact-stroller/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2FReact-stroller/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/theKashey%2FReact-stroller/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/theKashey","download_url":"https://codeload.github.com/theKashey/React-stroller/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233984692,"owners_count":18761311,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","scroll","scrollbar"],"created_at":"2024-11-10T16:40:40.366Z","updated_at":"2025-09-23T15:31:22.125Z","avatar_url":"https://github.com/theKashey.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003ch1\u003eReact-S\u003csub\u003ec\u003c/sub\u003e\u003cb\u003et\u003c/b\u003eroller 📜🏃‍\u003c/h1\u003e\n  \u003cbr/\u003e\n\n  \u003ca href=\"https://travis-ci.org/github/theKashey/react-stroller\"\u003e\n    \u003cimg src=\"https://travis-ci.org/theKashey/react-stroller.svg\" /\u003e\n  \u003c/a\u003e\n  \n  \u003ca href=\"https://www.npmjs.com/package/react-stroller\"\u003e\n   \u003cimg src=\"https://img.shields.io/npm/v/react-stroller.svg?style=flat-square\" /\u003e\n  \u003c/a\u003e\n  \n  \u003cbr/\u003e  \n\u003c/div\u003e  \n\n-----\nThe right page scroller - browser friendly custom draggable scrollbars.\n[Demo](https://codesandbox.io/s/mm5xq5kv5y) \n\n# Capabilities\n\n- ⛓display any custom scroll bar, even, well, [nyan-cat](https://github.com/theKashey/react-nyan-stroller)🐈🏳️‍🌈🏳️‍🌈🏳️‍🌈 scroll bar\n- 📜 vertical and horizontal, as well as not matching main scroll axis - like displaying horizontal \"reading indicator\" for the vertical scroll.\n- 👨‍🔬display scrollbar 1) inside 2) outside 3) at window the target scrollable\n- 🤓support for \"ScrollIndicators\", and actually any other \"custom\" 🤹‍♀️ effects\n- 🚀support for passive scroll observation (🥳 performance)\n- 🧸easy to use out of the box/fully customizable.\n\n# API\nStroller provides 4 components - to create Scrollable `container`, to draw a `scroll bar` and\nto `combine` all together. The 4th component is a magic one - `StrollCaptor`.\n\nWritten in TypeScript. IDE should provide 100% prop competition.\n\nProvides friction-less expirience, as long stroller does not hook into `onwheel` event,\nobserving browser scroll silently, keeping all animations smooth.\n\nCould be used inside and outside scrollable node, autodetecting nearest scrollable parent.\n\n```js\nimport {StrollableContainer} from 'react-stroller';\n\n\u003cBlockWithHeightSet\u003e\n  \u003cStrollableContainer draggable\u003e\n    \u003cUL/\u003e\n  \u003c/StrollableContainer\u003e\n\u003c/BlockWithHeightSet\u003e\n```\n\nReact-stroller consists from 3 parts:\n- `Strollable` - \"scrollable\" container. It will remove native browser scroll.\n- `Stroller` - the main component, containing all the logic\n- `StrollCaptor` - component, which bypasses scrollable elements, finding the nodes to control.\n\n`StrollableContainer` - just combines them all in the right order.\n\n### Strollable\nIs a scrollable, but __scroll-bar-less container__. It uses _padding-hack_ to hide browser scrollbars\non any system.\n\nRead more about scroll bars here - [Scroll to the future](https://evilmartians.com/chronicles/scroll-to-the-future-modern-javascript-css-scrolling-implementations)\n\n```js\nimport {Strollable} from 'react-stroller';\n\n\u003cdiv className=\"styleWithSizeDefined\"\u003e\n    \u003cStrollable axis=\"horizontal | vertical\" [gap]={gapFromScroll}\u003e\n     Strollable will consume 100% width/height - all the possible space \n     setup `position:relative` to the child\n     and display any content inside\n    \u003c/Strollable\u003e \n\u003c/div\u003e\n```\n\n### Stroller\nStroller is a React-scrollbar. It observes `scroll` event, and position itself where it should be.\nStroller likes to be placed inside Strollable.\n\nMeanwhile could be used to scroll \"unscrollable\"(unwheelable) containers.\n```js\nimport {Stroller} from 'react-stroller';\n\n\u003cdiv style={{ position:'relative', overflow: 'hidden'}}\u003e\n  \u003cStroller\n    // drop drop Scroller anywhere inside scrollable node \n    // all props are optional\n    axis=\"horizontal | vertical\"\n    bar={() =\u003e\u003cdiv\u003eYour Own scroll _bar_ implementation\u003c/div\u003e}\n    scrollBar={() =\u003e \u003cdiv\u003eYour Own __scroll bar__ implementation\u003c/div\u003e}\n    oppositePosition /* if you want scroll bar on left, or top */\n    draggable /* should it be draggable? */     \n    barHeight={(height, scrollHeight, {dragging}) =\u003e dragging ? 42 : 24} /* you can override scroll element height */\n    scrollKey={any} // key to indicate that stroller should update data (scroll height)\n    passive={true} // enable passive scroll observation. Better for perf, worse for scroll synchronization\n    onScroll={() =\u003e {}} // handle scroll event\n  /\u003e\n\u003c/div\u003e\n```\nStroller will find nearest scrollable parent, and set a scroll bar.\n`bar`, you can override is just a view, an internal node for a _real_ Bar Stroller will \ndraw itself. `bar` should fill 100% height and 100% width, and be just _style_. \n\n`scrollBar` property currently is not documented, and used only by [react-nyan-scroll](https://github.com/theKashey/react-nyan-stroller).\n\n### StrollableContainer\nJust combine all Components together in the right order\n```js\nimport {StrollableContainer} from 'react-stroller';\n\n\u003cdiv style={{height:'100500px'}}\u003e\n    \u003cStrollableContainer [gap]={marginFromScroller} [scrollKey]={any}\u003e\n      any content\n    \u003c/StrollableContainer\u003e\n\u003c/div\u003e\n``` \n\n- __Do not set `overflow` property for StrollableContainer's parent__, as long it will \nset it for itself.\n- Always __set height__, you can change it via `flex-grow`, or `flex-shrink`, but it has to be set.\n\n### StrollCaptor - the secret sauce\nBy default Stroller could be not super smooth, as long it will be first \"scrolled\"\nas a part of scrollable node content, and then will be moved to a new position.\n\nIt is natural to have some visual glitches and jumps, if you are not controlling wheel and emulating\nscroll event as any other \"custom-scroll-bar\" does.\n\n`StrollCaptor` is a fix - place it __inside__ scrollable node, while placing Stroller __outside__.\nAs result - on component scroll Strolled will not be moved, removing any possible _jumps_.\n```js\n\u003cdiv style={{position:'relative'}}\u003e\n  \u003cStroller\u003e\n     \u003cdiv style={{height:500}}\u003e\n       \u003cStrollableContainer\u003e // this is optional\n         \u003cStrollCaptor /\u003e\n          // StrollCaptor will report to Stroller about his scrollable parent\n          // which is a child for Stroller, and invisible by default.\n       \u003c/StrollableContainer\u003e\n     \u003c/div\u003e\n  \u003c/Stroller\u003e\n\u003c/div\u003e\n```\n\n### StrollerState\nIt's possible to create \"Virtual Container\", similar to `react-window`, using React-Strollable.\n\nStroller will expose internal state via `StrollerState` component, you can _consume_ and then react\nto scroll or resize.\n```js\n\u003cStrollableContainer\u003e\n  \u003cStrollerState\u003e\n   {({\n     scrollWidth: number,\n     scrollHeight: number,\n   \n     clientWidth: number,\n     clientHeight: number,\n   \n     scrollLeft: number,\n     scrollTop: number,\n   }) =\u003e (\n     // render elements based on visibility.\n   )}\n  \u003c/StrollerState\u003e\n\u003c/StrollableContainer\u003e\n```\n\n## ScrollIndicators\nJust read stroller state and display them\n```js\nimport {StrollerState} from 'react-stroller';\nexport const VerticalScrollIndicator= () =\u003e (\n  \u003cStrollerState\u003e\n    {({scrollTop, scrollHeight, clientHeight}) =\u003e (\n      \u003c\u003e\n        \u003cspan          \n          className={cx(\n            styles['indicator--top'],            \n            scrollTop === 0 \u0026\u0026 styles['indicator--hidden']\n          )}\n        /\u003e\n        \u003cspan\n          className={cx(\n            styles['indicator--bottom'],\n            scrollTop + clientHeight \u003e= scrollHeight \u0026\u0026 styles['indicator--hidden']\n          )}\n        /\u003e\n      \u003c/\u003e\n    )}\n  \u003c/StrollerState\u003e\n);\n```\n\n## Separated scrollbar\nYou might display scrollbar in the parent, while observing scroll at the children\n```js\n\u003cStroller\u003e // \"Bar\" would be displayed on this level\n  any code\n  \u003cDivWithKnownHeight\u003e // we are \"observing\" scroll in this node\n    \u003cStrollable\u003e \n      \u003cStrollCaptor/\u003e\n        {children}\n    \u003c/Strollable\u003e\n    \u003cVerticalScrollIndicator/\u003e\n  \u003c/DivWithKnownHeight\u003e\n  any code\n\u003c/Stroller\u003e            \n```\n\n## Testing\nReact-stroller is a library, which could not be unit tested. Things like smooth scroll, right overflows and\n touch-n-feel experience are not something robot could test.   \nTested manually and carefully by a human being. \n\nUses TypeScript and a finite state machine(Faste) underneath, for a better confidence.\n\n# See also\n\n[react-custom-scrollbars](https://github.com/malte-wessel/react-custom-scrollbars) - another great package for custom scrollbars\n\n[React-Locky](https://github.com/theKashey/react-locky) - gather a full control under your scroll.\n\n[React-focus-lock](https://github.com/theKashey/react-focus-lock) - scope your focus in browser friendly way.\n\n# Licence \nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthekashey%2Freact-stroller","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthekashey%2Freact-stroller","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthekashey%2Freact-stroller/lists"}