{"id":15284408,"url":"https://github.com/rdmurphy/scroll-scene-element","last_synced_at":"2025-07-19T22:04:23.957Z","repository":{"id":46146025,"uuid":"471449587","full_name":"rdmurphy/scroll-scene-element","owner":"rdmurphy","description":"📜 A tiny custom element for all your scrollytelling needs!","archived":false,"fork":false,"pushed_at":"2022-04-29T03:18:53.000Z","size":312,"stargazers_count":27,"open_issues_count":2,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-06-05T06:25:59.758Z","etag":null,"topics":["custom-elements","javascript","scrollytelling","web-components"],"latest_commit_sha":null,"homepage":"https://rdmurphy.github.io/scroll-scene-element/sticky","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/rdmurphy.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}},"created_at":"2022-03-18T16:59:03.000Z","updated_at":"2024-09-05T06:54:38.000Z","dependencies_parsed_at":"2022-08-25T12:11:35.754Z","dependency_job_id":null,"html_url":"https://github.com/rdmurphy/scroll-scene-element","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/rdmurphy/scroll-scene-element","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdmurphy%2Fscroll-scene-element","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdmurphy%2Fscroll-scene-element/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdmurphy%2Fscroll-scene-element/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdmurphy%2Fscroll-scene-element/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rdmurphy","download_url":"https://codeload.github.com/rdmurphy/scroll-scene-element/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rdmurphy%2Fscroll-scene-element/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266026178,"owners_count":23866030,"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":["custom-elements","javascript","scrollytelling","web-components"],"created_at":"2024-09-30T14:56:03.735Z","updated_at":"2025-07-19T22:04:23.761Z","avatar_url":"https://github.com/rdmurphy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `\u003cscroll-scene\u003e` element\n\nA tiny custom element for all your scrollytelling needs! The successor to [`@newswire/scroller`](https://github.com/rdmurphy/scroller).\n\n## Key features\n\n- 🐜 **~700 bytes** brotli'ed, **~800 bytes** gzip'ed\n- 👀 Uses a highly-performant **[Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)** to monitor scrolling changes\n- 📚 Smartly uses scroll events to **calculate scroll progress** only when needed\n- 🌻 Each `\u003cscroll-scene\u003e` element may **have its own** `offset` and **opt-in** to `progress` events\n- 🙅🏽‍ **No dependencies**\n\n## Examples\n\n- [Basic usage](https://rdmurphy.github.io/scroll-scene-element/basic)\n- [Sticky graphics](https://rdmurphy.github.io/scroll-scene-element/sticky)\n- [Progress events](https://rdmurphy.github.io/scroll-scene-element/progress)\n\n## Installation\n\n```sh\nnpm install scroll-scene-element\n// or\nyarn add scroll-scene-element\n// or\npnpm add scroll-scene-element\n```\n\n## Usage\n\nIn your HTML add `\u003cscroll-scene\u003e` container elements around every \"scene\" you want to track the progression of in your interactive. Feel free to use these elements as the containers of your graphics or other dynamic content and style them as needed - all progression and scroll depth changes will be tracked on the tag and its contents.\n\n```html\n\u003cdiv class=\"scrollytelling-container\"\u003e\n\t\u003cscroll-scene\u003e\n\t\t\u003ch2\u003eScene 1\u003c/h2\u003e\n\t\t\u003cp\u003eThis is the first scene.\u003c/p\u003e\n\t\u003c/scroll-scene\u003e\n\t\u003cscroll-scene\u003e\n\t\t\u003ch2\u003eScene 2\u003c/h2\u003e\n\t\t\u003cp\u003eThis is the first scene.\u003c/p\u003e\n\t\u003c/scroll-scene\u003e\n\t\u003cscroll-scene\u003e\n\t\t\u003ch2\u003eScene 3\u003c/h2\u003e\n\t\t\u003cp\u003eThis is the first scene.\u003c/p\u003e\n\t\u003c/scroll-scene\u003e\n\u003c/div\u003e\n```\n\nThen import the script as an ES module in your bundle or load via a script tag to upgrade the `\u003cscroll-scene\u003e` elements:\n\n```js\nimport 'scroll-scene-element';\n```\n\n_or_\n\n\u003c!-- prettier-ignore --\u003e\n```html\n\u003cscript src=\"https://unpkg.com/scroll-scene-element/dist/scroll-scene-element.js\" type=\"module\"\u003e\u003c/script\u003e\n```\n\nIf you have experience with [Scrollama](https://github.com/russellgoldenberg/scrollama) or [`@newswire/scroller`](https://github.com/rdmurphy/scroller) it may be surprising that there's no \"init\" step. Thanks to custom elements the initalization happens automatically just by using `\u003cscroll-scene\u003e`.\n\nEvents with `\u003cscroll-scene\u003e` work just like others in JavaScript giving you the same amount of flexibility. (And familiarity!) `scroll-scene-enter`, `scroll-scene-exit` and `scroll-scene-progress` all bubble up to `document`. If you know there will only be a single set of `\u003cscroll-scene\u003e` elements on a page you may listen on `document` directly:\n\n```js\ndocument.addEventListener('scroll-scene-enter', (event) =\u003e {\n\t// \"event\" is a CustomEvent, giving it has a `detail` property\n\tconst detail = event.detail;\n\n\t// the triggering element\n\tconst element = event.element;\n\n\t// just like in standard DOM events, \"target\" is also the triggering element\n\tconst target = event.target;\n\n\t// the bounds of the triggering element\n\tconst bounds = detail.bounds;\n\n\t// whether the page was scrolling up or down when the event was triggered\n\tconst isScrollingDown = detail.isScrollingDown;\n\n\t// the offset used for this element\n\tconst offset = detail.offset;\n});\n```\n\nBut what if you have more than one set of `\u003cscroll-scene\u003e` elements on a page? You might instead attach your listener to a parent element of each set of `\u003cscroll-scene\u003e` elements:\n\n```js\nconst container = document.querySelector('.scrollytelling-container');\n\ncontainer.addEventListener('scroll-scene-enter', (event) =\u003e {\n\t// no need to allow it to bubble up to `document`\n\tevent.stopPropagation();\n\n\t// \"event\" is a CustomEvent, giving it has a `detail` property\n\tconst detail = event.detail;\n\n\t// ...\n});\n```\n\nAnd finally - you may attach your listener to each `\u003cscroll-scene\u003e` element individually:\n\n```js\nconst scenes = document.querySelectorAll('scroll-scene');\n\nscenes.forEach((scene) =\u003e {\n\tscene.addEventListener('scroll-scene-enter', (event) =\u003e {\n\t\t// no need to allow it to bubble up to `document`\n\t\tevent.stopPropagation();\n\n\t\t// \"event\" is a CustomEvent, giving it has a `detail` property\n\t\tconst detail = event.detail;\n\n\t\t// ...\n\t});\n});\n```\n\nMaybe you only need to know the first time a scene enters (or exits) the viewport? You can use the native `once` option with `addEventListener`:\n\n```js\nconst scene = document.querySelector('scroll-scene');\n\nscene.addEventListener(\n\t'scroll-scene-enter',\n\t() =\u003e {\n\t\tconsole.log('Entered!');\n\t},\n\t{ once: true },\n);\n\nscene.addEventListener(\n\t'scroll-scene-exit',\n\t() =\u003e {\n\t\tconsole.log('Exited!');\n\t},\n\t{ once: true },\n);\n```\n\nIf a `\u003cscroll-scene\u003e` element opts-in to `progress` tracking, it will emit a `scroll-scene-progress` event when the progress changes once it enters and stop emitting the event once it exits. This event will bubble up to `document`:\n\n```html\n\u003cscroll-scene progress\u003e\n\t\u003ch2\u003eScene 1\u003c/h2\u003e\n\t\u003cp\u003eThis is the first scene.\u003c/p\u003e\n\u003c/scroll-scene\u003e\n```\n\n```js\nconst scene = document.querySelector('scroll-scene');\n\nscene.addEventListener('scroll-scene-progress', (event) =\u003e {\n\t// \"event\" is a CustomEvent, giving it has a `detail` property\n\tconst detail = event.detail;\n\n\t// the triggering element\n\tconst element = event.element;\n\n\t// `event.target` is also the triggering element, just like in standard DOM events\n\tconst target = event.target;\n\n\t// the bounds of the triggering element\n\tconst bounds = detail.bounds;\n\n\t// the offset used for this element\n\tconst offset = detail.offset;\n\n\t// the progress of the element from 0 to 1\n\tconst progress = detail.progress;\n});\n```\n\n## Attributes\n\nA `\u003cscroll-scene\u003e` element has two optional attributes:\n\n- `offset`: a number between 0 and 1 that determines how far from the top of the viewport the element must be before a `scroll-scene-enter` or `scroll-scene-exit` event is triggered. Defaults to `0.5`.\n- `progress`: a boolean that determines whether the `scroll-scene-progress` event is triggered. Defaults to `false`.\n\nThese can be set on the `\u003cscroll-scene\u003e` element as an attribute or be passed in as a property.\n\n```html\n\u003cscroll-scene offset=\"0.75\"\u003e\u003c/scroll-scene\u003e\n\u003cscroll-scene progress\u003e\u003c/scroll-scene\u003e\n```\n\n```js\nconst scene = document.querySelector('scroll-scene');\n\n// as properties\nscene.offset = 0.75;\nscene.progress = true;\n\n// as attributes\nscene.setAttribute('offset', '0.75');\nscene.setAttribute('progress', '');\n```\n\n## Events\n\n### Viewport events\n\n**`scroll-scene-enter`** is emit when an element enters the viewport. **`scroll-scene-exit`** is emit when an element exits the viewport. Both events bubble up to `document`. They both have a `detail` property that contains the following:\n\n- `bounds`: the bounds ([`DOMRectReadOnly`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRectReadOnly)) of the triggering element as made available within the `IntersectionObserver` callback\n- `element`: the triggering element\n- `isScrollingDown`: whether the page was scrolling up or down when the event was triggered\n- `offset`: the offset used for this element\n\n### Progress event\n\n**`scroll-scene-progress`** is emitted when the progress of an element changes. It bubbles up to `document` and has a `detail` property that contains the following:\n\n- `bounds`: the bounds ([`DOMRect`](https://developer.mozilla.org/en-US/docs/Web/API/DOMRect)) of the triggering element\n- `element`: the triggering element\n- `offset`: the offset used for this element\n- `progress`: the progress of the element from 0 to 1\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frdmurphy%2Fscroll-scene-element","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frdmurphy%2Fscroll-scene-element","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frdmurphy%2Fscroll-scene-element/lists"}