{"id":16922146,"url":"https://github.com/julien-marcou/scrollable-component","last_synced_at":"2025-03-22T11:30:57.479Z","repository":{"id":45242240,"uuid":"276081015","full_name":"Julien-Marcou/Scrollable-Component","owner":"Julien-Marcou","description":"Native viewport with custom scrollbars 🖱️","archived":false,"fork":false,"pushed_at":"2022-07-21T19:48:41.000Z","size":44,"stargazers_count":17,"open_issues_count":2,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-12T15:50:36.962Z","etag":null,"topics":["custom-element","customizable","native","scroll","scrollbar","viewport","web-component"],"latest_commit_sha":null,"homepage":"https://scrollable.julien-marcou.fr","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/Julien-Marcou.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":"2020-06-30T11:34:40.000Z","updated_at":"2025-01-08T11:46:02.000Z","dependencies_parsed_at":"2022-08-12T11:50:48.850Z","dependency_job_id":null,"html_url":"https://github.com/Julien-Marcou/Scrollable-Component","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Julien-Marcou%2FScrollable-Component","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Julien-Marcou%2FScrollable-Component/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Julien-Marcou%2FScrollable-Component/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Julien-Marcou%2FScrollable-Component/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Julien-Marcou","download_url":"https://codeload.github.com/Julien-Marcou/Scrollable-Component/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244951194,"owners_count":20537334,"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-element","customizable","native","scroll","scrollbar","viewport","web-component"],"created_at":"2024-10-13T19:54:19.504Z","updated_at":"2025-03-22T11:30:57.040Z","avatar_url":"https://github.com/Julien-Marcou.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Scrollable Component\n\n[![NPM Package](https://img.shields.io/npm/v/scrollable-component?label=release\u0026color=%23cd2620\u0026logo=npm)](https://www.npmjs.com/package/scrollable-component)\n[![GitHub Repository](https://img.shields.io/github/stars/Julien-Marcou/Scrollable-Component?color=%23f5f5f5\u0026logo=github)](https://github.com/Julien-Marcou/Scrollabe-Component)\n\n![Downloads per Month](https://img.shields.io/npm/dm/scrollable-component)\n![Gzip Size](https://img.shields.io/bundlephobia/minzip/scrollable-component?label=gzip%20size)\n![No Dependency](https://img.shields.io/badge/dependencies-none-%23872a84)\n![MIT License](https://img.shields.io/npm/l/scrollable-component)\n\nScrollable Component is a custom element (Web Component) made to handle native scrolling with a custom scrollbar, which means it is not trying to mimic or override the viewport's native scrolling, but instead, uses the viewport's native scrolling to mimic a custom scrollbar.\n\n```html\n\u003cscrollable-component\u003e\u003c/scrollable-component\u003e\n```\n\n\n## Demo\n\nYou can check out some examples [here](https://scrollable.julien-marcou.fr/).\n\nAnd here is a screenshot of a native scrollbar (on Windows 10) vs the default scrollbar provided by Scrollable Component :\n\n![Native vs Custom scrollbar](https://github.com/Julien-Marcou/scrollable-component-demo/raw/main/native-vs-custom.png)\n\n\n## Installation\n\n```shell\nnpm install scrollable-component\n```\n\n\n## Usage\n\nThis NPM package uses the ECMAScript Modules system, so the easiest way to use it, is with a Bundler (like WebPack), so you don't have to worry about how to make it available and import it.\n\n### With a Bundler\n\nAs it is a self-defined custom element, you must import it only once in your main entry file so it's available everywhere :\n\n```javascript\nimport 'scrollable-component';\n```\n\nIn addition to the previous import, if you are using TypeScript, and want the typing of the `ScrollableComponentElement`, you can import it where you need it :\n\n```typescript\nimport { ScrollableComponentElement } from 'scrollable-component';\n```\n\n### Without a Bundler\n\nIf you are not using a bundler, you'll have to expose the `scrollable-component/index.js` file so it is accessible from the web, and import it in your HTML using a `module` script.\n\n#### Using the full path\n\n```html\n\u003cscript type=\"module\" src=\"/node_modules/scrollable-component/index.js\"\u003e\u003c/script\u003e\n\n\u003c!-- or --\u003e\n\n\u003cscript type=\"module\"\u003e\n  import '/node_modules/scrollable-component/index.js';\n\u003c/script\u003e\n```\n\n#### Using Import Maps\n\n[Import Maps](https://wicg.github.io/import-maps/) can be very useful when you have several dependencies between different modules, as it allows you to import modules using their names instead of their full path.\n\nBut they are not implemented in any browser yet, so you'll have to use a polyfill :\n\n```html\n\u003cscript async src=\"https://unpkg.com/es-module-shims@0.12.1/dist/es-module-shims.js\"\u003e\u003c/script\u003e\n\u003cscript type=\"importmap-shim\"\u003e\n  {\n    \"imports\": {\n      \"scrollable-component\": \"/node_modules/scrollable-component/index.js\"\n    }\n  }\n\u003c/script\u003e\n\u003cscript type=\"module-shim\"\u003e\n  import 'scrollable-component';\n\u003c/script\u003e\n```\n\n\n## Documentation\n\nThe `ScrollableComponentElement` will automatically add custom scrollbars if the content overflows the height/width of the viewport, so you just have to constrain its size (using height, max-height, or whatever you want) :\n\n```html\n\u003cstyle\u003e\n  .my-content {\n    height: 300px;\n  }\n\u003c/style\u003e\n\n\u003cscrollable-component class=\"my-content\"\u003e\n  \u003c!-- Your content --\u003e\n\u003c/scrollable-component\u003e\n```\n\nBy default, the scrollbar only appears when hovering the viewport, but you can force the scrollbar to always be visible by setting the `scrollbar-visibility` attribute to `always`\n\n```html\n\u003cscrollable-component scrollbar-visibility=\"always\"\u003e\n  \u003c!-- Your content --\u003e\n\u003c/scrollable-component\u003e\n```\n\nYou can put the vertical scrollbar on the left of the viewport by setting the `vertical-scrollbar-position` attribute to `left`\n\n```html\n\u003cscrollable-component vertical-scrollbar-position=\"left\"\u003e\n  \u003c!-- Your content --\u003e\n\u003c/scrollable-component\u003e\n```\n\nYou can put the horizontal scrollbar on the top of the viewport by setting the `horizontal-scrollbar-position` attribute to `top`\n\n```html\n\u003cscrollable-component horizontal-scrollbar-position=\"top\"\u003e\n  \u003c!-- Your content --\u003e\n\u003c/scrollable-component\u003e\n```\n\nBy default, the viewport's content will overflow in both directions, if you have some content which you want to be hidden instead of displaying a scrollbar to access it, you can override the viewport overflow behaviors using CSS properties\n\n```css\n/* No horizontal scrolling */\nscrollable-component {\n  --viewport-overflow-x: hidden;\n}\n\n/* No vertical scrolling  */\nscrollable-component {\n  --viewport-overflow-y: hidden;\n}\n```\n\nIf can access the native viewport of a scrollable-component like this :\n\n```javascript\nconst scrollableComponent = document.querySelector('scrollable-component');\n\nscrollableComponent.viewport.addEventListener('scroll', (event) =\u003e {\n  // Your code\n});\n```\n\nEach scrollable-component is defining its own `--viewport-width` \u0026 `--viewport-height` CSS properties, which may be useful if you want to create something like a carousel, where child elements must take a certain amount of the viewport's size\n\n```html\n\u003cstyle\u003e\n  .carousel .carousel-track {\n    display: grid;\n    grid-auto-flow: column;\n    grid-gap: 30px;\n  }\n  .carousel .carousel-item {\n    width: var(--viewport-width);\n    height: 300px;\n  }\n\u003c/style\u003e\n\n\u003cscrollable-component class=\"carousel\"\u003e\n  \u003cdiv class=\"carousel-track\"\u003e\n    \u003cdiv class=\"carousel-item\"\u003eSlide 1\u003c/div\u003e\n    \u003cdiv class=\"carousel-item\"\u003eSlide 2\u003c/div\u003e\n    \u003cdiv class=\"carousel-item\"\u003eSlide 3\u003c/div\u003e\n    \u003cdiv class=\"carousel-item\"\u003eSlide 4\u003c/div\u003e\n    \u003cdiv class=\"carousel-item\"\u003eSlide 5\u003c/div\u003e\n    \u003cdiv class=\"carousel-item\"\u003eSlide 6\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/scrollable-component\u003e\n```\n\n\n## Customization\n\nYou can change the transitions, the scrolling behaviors and the look of the scrollbars using CSS properties.\n\n![Native vs Custom scrollbar](https://raw.githubusercontent.com/Julien-Marcou/scrollable-component-demo/main/customization.png)\n\nHere is the list of all the default CSS properties you can override :\n\n```css\nscrollable-component {\n  /* Transitions */\n  --fade-in-transition-duration: 150ms;\n  --fade-out-transition-duration: 800ms;\n  --fade-out-transition-delay: 300ms;\n  --fill-color-transition-duration: 150ms;\n\n  /* Overflow behaviors */\n  --viewport-overflow-x: auto;\n  --viewport-overflow-y: auto;\n\n  /* Scrolling behaviors */\n  --viewport-scroll-snap-type: none;\n  --viewport-scroll-behavior: auto;\n  --viewport-overscroll-behavior: auto;\n  --viewport-z-index: 0;\n\n  /* Scrollbar look */\n  --scrollbar-width: 16px;\n  --scrollbar-padding: 2px;\n  --scrollbar-fill-color: transparent;\n  --scrollbar-fill-color-hover: transparent;\n  --scrollbar-border: 0 none;\n  --scrollbar-border-radius: 0;\n  --scrollbar-box-shadow: none;\n  --scrollbar-z-index-hover: 30;\n  --vertical-scrollbar-padding: var(--scrollbar-padding);\n  --vertical-scrollbar-background: none;\n  --vertical-scrollbar-background-size: auto;\n  --vertical-scrollbar-z-index: 20;\n  --horizontal-scrollbar-padding: var(--scrollbar-padding);\n  --horizontal-scrollbar-background: none;\n  --horizontal-scrollbar-background-size: auto;\n  --horizontal-scrollbar-z-index: 10;\n\n  /* Scrollbar's track look */\n  --scrollbar-track-fill-color: transparent;\n  --scrollbar-track-fill-color-hover: transparent;\n  --scrollbar-track-border: 0 none;\n  --scrollbar-track-border-radius: 0;\n  --scrollbar-track-box-shadow: none;\n  --vertical-scrollbar-track-background: none;\n  --vertical-scrollbar-track-background-size: auto;\n  --horizontal-scrollbar-track-background: none;\n  --horizontal-scrollbar-track-background-size: auto;\n\n  /* Scrollbar's thumb look */\n  --scrollbar-thumb-fill-color: #ccc;\n  --scrollbar-thumb-fill-color-hover: #aaa;\n  --scrollbar-thumb-border: 0 none;\n  --scrollbar-thumb-border-radius: var(--scrollbar-width);\n  --scrollbar-thumb-box-shadow: none;\n  --vertical-scrollbar-thumb-background: none;\n  --vertical-scrollbar-thumb-background-size: auto;\n  --horizontal-scrollbar-thumb-background: none;\n  --horizontal-scrollbar-thumb-background-size: auto;\n\n  /* Content padding */\n  /* (You probably want to use this instead of setting the padding directly on the scrollable-component) */\n  --content-padding: 0;\n}\n```\n\n\n## Browser compatibility\n\nFirefox, Chromium-based browsers (Chrome, Edge, Opera, ...) \u0026 WebKit-based browsers (Safari, ...)\n\n\n## Why use Scrollable Component ?\n\n### Perks\n\nSimple, performant, modern, it probably outpasses a lot of old custom scrollbar packages\n\n- It's built for raw performance by using modern features from browsers, which also allow for better customization \u0026 cleaner code\n- It does not override the viewport's native behaviors (Mouse Wheel scrolling, Swipe scrolling, Page Down/Up keys, Arrow keys, Middle Mouse Button's auto-scrolling, Scroll snapping, JavaScript API...)\n- It uses the [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components) specs, making it act like a black box from the outside (encapsulating HTML, CSS \u0026 JS) and leaving the DOM untouched, without extraneous `\u003cdiv\u003e`\n- It's simple to use (you just need to add the `\u003cscrollable-component\u003e` tag around the content you want the custom scrollbars on)\n- It's easy to customize (it uses CSS variables, like `--scrollbar-width: 16px;`)\n\n### Quirks\n\nThis package is not intended to replace all the scrollbars of your website, especially not the body's one. Tampering with native behaviors is always at risk, especially for the Web Accessibility\n\nIt's recommended to only use it sparingly, on small parts of your website (like modal boxes, chats, sidebars, dropdowns...) to enhance the user's experience through a cleaner UI\n\n- It only works on modern browsers\n- It will never be as fast as native scrollbars\n- It sacrifices some native functionalities (like Google Chrome's search result highlights in the scrollbar)\n- The custom scrollbars are absolutely positioned above the native viewport, which means scrolling when the pointer directly interacts with them instead of the viewport, is in fact, handled with some JavaScript and not natively\n\n\n## How it works\n\nScrollable Component uses the [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components) specs to create a custom element which handles all the work for you and which can even be extended\n\nThe native scrollbar is hidden using the CSS `scrollbar-width: none;` rule which is a powerful new feature in the state of [Candidate Recommendation Snapshot](https://www.w3.org/TR/css-scrollbars-1/), but already supported by Firefox and that should come to Chromium-based \u0026 WebKit-based browsers soon enough, which are for the moment falling back to the CSS `::-webkit-scrollbar { width: 0; }` rule\n\nThe custom scrollbar is redrawn when needed, to visually match where the native scrollbar would be placed\n\nAll scrolling behaviors on the viewport itself are the native ones, while scrolling behaviors directly using the custom scrollbar (e.g. drag \u0026 dropping the scrollbar's thumb or clicking somewhere on the scrollbar's track) are handled with some JavaScript which then natively move the viewport's scroll position\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulien-marcou%2Fscrollable-component","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjulien-marcou%2Fscrollable-component","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjulien-marcou%2Fscrollable-component/lists"}