{"id":17025841,"url":"https://github.com/jsonkao/react-scrollama","last_synced_at":"2025-04-08T13:00:24.225Z","repository":{"id":37850373,"uuid":"142162018","full_name":"jsonkao/react-scrollama","owner":"jsonkao","description":"Simple scrollytelling with the IntersectionObserver in React.","archived":false,"fork":false,"pushed_at":"2025-03-19T16:26:23.000Z","size":9273,"stargazers_count":394,"open_issues_count":13,"forks_count":30,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-04-01T12:00:14.988Z","etag":null,"topics":["intersection-observer","react","scrollytelling"],"latest_commit_sha":null,"homepage":"https://jsonkao.github.io/react-scrollama","language":"JavaScript","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/jsonkao.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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-07-24T13:25:05.000Z","updated_at":"2025-03-25T17:41:54.000Z","dependencies_parsed_at":"2023-12-06T14:30:30.827Z","dependency_job_id":"9837a33e-3dd5-410f-a80b-8d6750b3e18b","html_url":"https://github.com/jsonkao/react-scrollama","commit_stats":{"total_commits":293,"total_committers":16,"mean_commits":18.3125,"dds":0.4812286689419796,"last_synced_commit":"8517fdaeac41af4ef95bc4af9be50ac91700ff2d"},"previous_names":[],"tags_count":29,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsonkao%2Freact-scrollama","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsonkao%2Freact-scrollama/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsonkao%2Freact-scrollama/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jsonkao%2Freact-scrollama/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jsonkao","download_url":"https://codeload.github.com/jsonkao/react-scrollama/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247847596,"owners_count":21006098,"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":["intersection-observer","react","scrollytelling"],"created_at":"2024-10-14T07:30:04.075Z","updated_at":"2025-04-08T13:00:24.138Z","avatar_url":"https://github.com/jsonkao.png","language":"JavaScript","readme":"# React Scrollama 🦙\n\n\u003cp align=\"left\"\u003e\n  \u003ca href=\"https://www.npmjs.com/package/react-scrollama\"\u003e\n    \u003cimg src=\"https://img.shields.io/npm/v/react-scrollama.svg\" alt=\"npm version\"/\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nReact Scrollama is a simple and silky library for scrollytelling. It relies on IntersectionObserver and sticky positioning over scroll listeners. It is originally adapted from [Russel Samora's](https://russellsamora.github.io/) [Scrollama](https://github.com/russellgoldenberg/scrollama).\n\nA few examples of ambitious interactive stories that were built with React Scrollama…\n\n\u003ctable\u003e\n\u003ctbody\u003e\n\u003ctr\u003e\n  \u003ctd\u003e\n    \u003ca href=\"https://www.worldbank.org/en/home\"\u003e\u003cimg src=\"https://www.worldbank.org/content/dam/wbr/logo/logo-wb-header-en.svg\" width=\"220\"/\u003e\u003c/a\u003e \u003cbr/\u003e \n    \u003ca href=\"https://datatopics.worldbank.org/sdgatlas/\"\u003e17 interactive visualization \u003cbr/\u003e\n      stories\u003c/a\u003e \u003ca href=\"https://twitter.com/maartenzam/status/1371951848039579664\"\u003eusing\u003c/a\u003e React Scrollama \u003cbr/\u003e\n    for scrollytelling\n  \u003c/td\u003e\n  \u003ctd\u003e\n    \u003ca href=\"https://datatopics.worldbank.org/sdgatlas/\"\u003e\u003cimg src=\"https://user-images.githubusercontent.com/15334952/111390361-fb04c480-8688-11eb-9fa1-3991ee73dd05.png\" width=\"450\"/\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003e\n    \u003ca href=\"https://www.leparisien.fr/\"\u003e\u003cimg src=\"https://www.leparisien.fr/pf/resources/images/E-LOGO-LP-192x60@2x.png?d=361\" width=\"150\" /\u003e\u003c/a\u003e \u003cbr/\u003e \u003ca href=\"https://www.leparisien.fr/paris-75/un-petit-magasin-devenu-un-symbole-de-paris-comment-tati-a-imprime-sa-marque-a-barbes-04-10-2021-IIJ5MJVO3RBZXJY2BMBJ626PEM.php\"\u003e\u003ci\u003eComment Tati a imprimé \u003cbr/\u003e sa marque à Barbès\u003c/i\u003e\u003c/a\u003e \u003cbr/\u003e by \u003ca href=\"https://twitter.com/fabianous\"\u003eFabien Casaleggio\u003c/a\u003e\n  \u003c/td\u003e\n  \u003ctd\u003e\n    \u003ca href=\"https://user-images.githubusercontent.com/15334952/136296998-d06fe550-3805-4053-a20c-be5ec42d5507.png\"\u003e\u003cimg src=\"https://user-images.githubusercontent.com/15334952/136296998-d06fe550-3805-4053-a20c-be5ec42d5507.png\" width=\"450\"/\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003e\n    \u003ca href=\"https://www.politico.com/\"\u003e\u003cimg src=\"https://static.politico.com/dims4/default/51786fe/2147483647/resize/1160x%3E/quality/90/?url=https%3A%2F%2Fstatic.politico.com%2F11%2F3c%2F2571c0ab455e91bf81dc4bab93a6%2Fpolitico-logo.png\" width=\"150\" /\u003e\u003c/a\u003e \u003cbr/\u003e \u003ca href=\"https://www.politico.com/interactives/2019/election-security-americas-voting-machines\"\u003e\u003ci\u003eThe scramble to secure \u003cbr/\u003e America’s voting machines\u003c/i\u003e\u003c/a\u003e \u003cbr/\u003e by \u003ca href=\"https://bzjin.github.io\"\u003eBeatrice Jin\u003c/a\u003e\n  \u003c/td\u003e\n  \u003ctd\u003e\n    \u003ca href=\"https://www.politico.com/interactives/2019/election-security-americas-voting-machines\"\u003e\u003cimg src=\"https://user-images.githubusercontent.com/15334952/111391036-2dfb8800-868a-11eb-9c64-3f322ef1e588.png\" width=\"450\"/\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003e\n    \u003ca href=\"http://graphicsdesk.github.io/\"\u003e\u003cimg src=\"https://s3.amazonaws.com/spec-imagehosting/spectator-logo.png\" width=\"180\"/\u003e\u003c/a\u003e\u003cbr/\u003e \u003ca href=\"https://www.columbiaspectator.com/eye-lead/graduate-sex-diversity\"\u003e\u003ci\u003eSex Diversity Among Grad \u003cbr/\u003e Students is Stagnating\u003c/i\u003e\u003c/a\u003e \u003cbr/\u003e by Jason Kao\n  \u003c/td\u003e\n  \u003ctd\u003e\n    \u003ca href=\"https://www.columbiaspectator.com/eye-lead/graduate-sex-diversity\"\u003e\u003cimg src=\"https://user-images.githubusercontent.com/15334952/111391310-b843ec00-868a-11eb-9744-72ee913cdbe1.png\" width=\"450\"/\u003e\u003c/a\u003e\n  \u003c/td\u003e\n\u003c/tr\u003e\n\u003c/tbody\u003e\n\u003c/table\u003e\n\n## Demo\n\nA live demo [lives here](https://jsonkao.github.io/react-scrollama). It was debu'd at the [August 2018 ReactNYC meetup](https://www.youtube.com/watch?v=zR_LDPLMUvE).\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth align=\"left\"\u003eBasic step triggers\u003c/th\u003e\n    \u003cth align=\"left\"\u003eSticky graphic on the side\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003cimg src=\"./example/public/demo-progress.gif\" /\u003e\u003c/td\u003e\n    \u003ctd width=\"65%\"\u003e\u003cimg src=\"./example/public/demo-sticky.gif\" /\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Install\n\nReact Scrollama can be installed as an [npm package](https://www.npmjs.com/package/react-scrollama):\n\n```\n$ npm install react-scrollama\n```\n\n## Usage\n\nA `Scrollama` component wraps a set of steps. Each `Step` component [must](https://github.com/jsonkao/react-scrollama/issues/19#issuecomment-624861326) wrap a DOM element (i.e. not just text).\n\n```jsx\n\u003cScrollama onStepEnter={callback} offset={0.5}\u003e\n  \u003cStep data={1}\u003e\n    \u003cdiv\u003e...\u003c/div\u003e\n  \u003c/Step\u003e\n  \u003cStep data={2}\u003e\n    \u003cdiv\u003e...\u003c/div\u003e\n  \u003c/Step\u003e\n\u003c/Scrollama\u003e\n```\n\n`\u003cScrollama\u003e` provides an interface for listening in on scroll triggers like entering or exiting a step. (Here's [a full list](#scrollama) of available props.)\n\nA basic example:\n\n```jsx\nimport React, { useState } from 'react';\nimport { Scrollama, Step } from 'react-scrollama';\n\nconst ScrollamaDemo = () =\u003e {\n  const [currentStepIndex, setCurrentStepIndex] = useState(null);\n\n  // This callback fires when a Step hits the offset threshold. It receives the\n  // data prop of the step, which in this demo stores the index of the step.\n  const onStepEnter = ({ data }) =\u003e {\n    setCurrentStepIndex(data);\n  };\n\n  return (\n    \u003cdiv style={{ margin: '50vh 0', border: '2px dashed skyblue' }}\u003e\n      \u003cdiv style={{ position: 'sticky', top: 0, border: '1px solid orchid' }}\u003e\n        I'm sticky. The current triggered step index is: {currentStepIndex}\n      \u003c/div\u003e\n      \u003cScrollama offset={0.5} onStepEnter={onStepEnter} debug\u003e\n        {[1, 2, 3, 4].map((_, stepIndex) =\u003e (\n          \u003cStep data={stepIndex} key={stepIndex}\u003e\n            \u003cdiv\n              style={{\n                margin: '50vh 0',\n                border: '1px solid gray',\n                opacity: currentStepIndex === stepIndex ? 1 : 0.2,\n              }}\n            \u003e\n              I'm a Scrollama Step of index {stepIndex}\n            \u003c/div\u003e\n          \u003c/Step\u003e\n        ))}\n      \u003c/Scrollama\u003e\n    \u003c/div\u003e\n  );\n};\n\nexport default ScrollamaDemo;\n```\n\n## API\n\nReact Scrollama components do not render into the DOM. They are meant to set up Intersection Observers on the elements inside the `\u003cStep\u003e` components. In the code above, only the `\u003cdiv\u003e` elements would show up in the DOM.\n\n### `Scrollama`\n\nThese are the props you can set on the `Scrollama` component itself:\n\n| Prop           | Type                                                 | Default | Description                                                                             |\n| -------------- | ---------------------------------------------------- | ------- | --------------------------------------------------------------------------------------- |\n| offset         | `number` (from 0 to 1) or pixel value (e.g. \"300px\") | 0.3     | How far from the top of the viewport to trigger a step (as a proportion of view height) |\n| threshold      | `number` (greater than 1)                            | 4       | Granularity of the progress interval in pixels (smaller = more granular)                |\n| onStepEnter    | `function`                                           |         | Callback that fires when the top or bottom edge of a step enters the offset threshold.  |\n| onStepExit     | `function`                                           |         | Callback that fires when the top or bottom edge of a step exits the offset threshold.   |\n| onStepProgress | `function`                                           |         | Callback that fires the progress a step has made through the threshold.                 |\n| debug          | `boolean`                                            | false   | Whether to show visual debugging tools.                                                 |\n\nThe `onStepEnter` and `onStepExit` callbacks receive one argument, an object, with the following properties:\n\n```js\n{\n  element, // The DOM node of the step that was triggered\n  data, // The data supplied to the step\n  direction, // 'up' or 'down'\n  entry, // the original `IntersectionObserver` entry\n}\n```\n\nThe `onStepProgress` callback receives one argument, an object, with the following properties:\n\n```js\n{\n  element, // The DOM node of the step that was triggered\n  data, // The data supplied to the step\n  progress, // The percent of completion of the step (0 to 1)\n  direction, // 'up' or 'down'\n  entry, // the original `IntersectionObserver` entry\n}\n```\n\nTo create a fixed graphic with text scrolling beside/over it, use `position: sticky;`. [How to use position sticky.](https://pudding.cool/process/scrollytelling-sticky/)\n\n### `Step`\n\nA `Step` element can contain one child, which must be a DOM element. To use a React component as the child node, it [must be wrapped with a DOM element](https://github.com/jsonkao/react-scrollama/issues/19#issuecomment-624861326) like `\u003cdiv\u003e`.\n\nThese are the props you can set on the `Step` component:\n\n| Prop | Type | Default | Description                                                      |\n| ---- | ---- | ------- | ---------------------------------------------------------------- |\n| data | any  |         | Data to be given to `\u003cScrollama\u003e` callbacks when step triggered. |\n\nYou will also probably want to set a `key` prop on each `Step` if you're transforming an array of data into a list of `Step` elements (see [Lists and Keys](https://reactjs.org/docs/lists-and-keys.html)).\n\n## Thank you to everyone who made this possible!\n\n- [jsonkao](https://github.com/jsonkao)\n- [maerzhase](https://github.com/maerzhase)\n- [NicholasLYang](https://github.com/NicholasLYang)\n- [jonesbp](https://github.com/jonesbp)\n- [kennethormandy](https://github.com/kennethormandy)\n- [cedricdelpoux](https://github.com/cedricdelpoux)\n- [davidnmora](https://github.com/davidnmora)\n- [jefffriesen](https://github.com/jefffriesen)\n- [paolocorti](https://github.com/paolocorti)\n- [elbertwang3](https://github.com/elbertwang3)\n- [michaelgrotton](https://github.com/michaelgrotton)\n- [jjrchrds](https://github.com/jjrchrds)\n- [goleary](https://github.com/goleary)\n- [danieleguido](https://github.com/danieleguido)\n- [Lane](https://github.com/Lane)\n- [jkjustjoshing](https://github.com/jkjustjoshing)\n- [tuckergordon](https://github.com/tuckergordon)\n- [fschwander](https://github.com/fschwander)\n- [thisispaul](https://github.com/thisispaul)\n\n## Features roadmap\n\n- Currently, there is no way to throttle/customize React Scrollama's [resize listener](https://github.com/jsonkao/react-scrollama/blob/master/src/Scrollama.js#L104) 😢. We're working on this in [#44](https://github.com/jsonkao/react-scrollama/issues/44).\n- Fire previous step triggers if they were jumped\n\nLmk if you need these features ASAP.\n","funding_links":[],"categories":["Data storytelling","JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsonkao%2Freact-scrollama","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjsonkao%2Freact-scrollama","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjsonkao%2Freact-scrollama/lists"}