{"id":25531950,"url":"https://github.com/evermade/overflow-slider","last_synced_at":"2026-02-20T08:03:42.642Z","repository":{"id":220506941,"uuid":"751853606","full_name":"evermade/overflow-slider","owner":"evermade","description":"Accessible and mobile-friendly slider library that is based on CSS overflow","archived":false,"fork":false,"pushed_at":"2025-12-10T16:48:37.000Z","size":556,"stargazers_count":17,"open_issues_count":2,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-12-11T02:31:22.271Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/evermade.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-02-02T13:24:26.000Z","updated_at":"2025-12-10T16:48:33.000Z","dependencies_parsed_at":"2025-04-11T11:50:03.143Z","dependency_job_id":null,"html_url":"https://github.com/evermade/overflow-slider","commit_stats":null,"previous_names":["evermade/overflow-slider"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/evermade/overflow-slider","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Foverflow-slider","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Foverflow-slider/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Foverflow-slider/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Foverflow-slider/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/evermade","download_url":"https://codeload.github.com/evermade/overflow-slider/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/evermade%2Foverflow-slider/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29645170,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-20T05:21:04.652Z","status":"ssl_error","status_checked_at":"2026-02-20T05:21:04.238Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2025-02-20T01:42:29.853Z","updated_at":"2026-02-20T08:03:42.636Z","avatar_url":"https://github.com/evermade.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Overflow Slider\n\nThis is slider library that is based on CSS overflow and progressive enhancements via JavaScript. The library is written in TypeScript but it requires no dependencies.\n\nThis library is heavily inspired by [Keen Slider](https://keen-slider.io/) and provides somewhat similar programming interface but with different engine running under the hood – CSS overflow.\n\nOverflow Slider aims to be lightweight, mobile-first and accessible. It is designed to be used in modern web projects and is very customizable and extendable via plugins and CSS.\n\n## Demos\n\n* [Example and demos](https://evermade.github.io/overflow-slider/)\n* [RTL demos](https://evermade.github.io/overflow-slider/index-rtl.html)\n\n## Getting started\n\nMarkup:\n\n```html\n\u003cdiv class=\"overflow-slider\"\u003e\n\t\u003cdiv\u003eSlide 1\u003c/div\u003e\n\t\u003cdiv\u003eSlide 2\u003c/div\u003e\n\t\u003cdiv\u003eSlide 3\u003c/div\u003e\n\u003c/div\u003e\n```\n\nYou don't have to use even class `overflow-slider` and slides can be whatever elements like `\u003ca\u003e`, `\u003cli\u003e`, or `article`.\n\nIf you’re using a bundler (such as Webpack or Rollup), you can install through npm:\n\n```bash\nnpm install @evermade/overflow-slider\n```\n\nImport the `OverflowSlider` along with plugins you want to use.\n\n```ts\nimport { OverflowSlider } from '@evermade/overflow-slider';\nimport DragScrollingPlugin from '@evermade/overflow-slider/plugins/drag-scrolling';\nimport SkipLinksPlugin from '@evermade/overflow-slider/plugins/skip-links';\nimport ArrowsPlugin from '@evermade/overflow-slider/plugins/arrows';\nimport ScrollIndicatorPlugin from '@evermade/overflow-slider/plugins/scroll-indicator';\nimport DotsPlugin from '@evermade/overflow-slider/plugins/dots';\n\n// minimal example\nconst minimalSlider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n);\n\n// example with plugins\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{\n\t\t// options here\n\t},\n\t[\n\t\tDragScrollingPlugin(),\n\t\tArrowsPlugin(),\n\t\tScrollIndicatorPlugin(),\n\t\tDotsPlugin(),\n\t\tSkipLinksPlugin(),\n\t]\n);\n\n// note that many plugins have their own settings so you can pass them as an object\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{\n\t\temulateScrollSnap: true,\n\t},\n\t[\n\t\tArrowsPlugin({\n\t\t\ttexts: {\n\t\t\t\tbuttonPrevious: 'Previous',\n\t\t\t\tbuttonNext: 'Next',\n\t\t\t},\n\t\t\ticons: {\n\t\t\t\tprev: '\u003csvg\u003e...\u003c/svg\u003e',\n\t\t\t\tnext: '\u003csvg\u003e...\u003c/svg\u003e',\n\t\t\t},\n\t\t\tclassNames: {\n\t\t\t\tnavContainer: 'my-nav-container',\n\t\t\t\tprevButton: 'my-prev-button',\n\t\t\t\tnextButton: 'my-next-button',\n\t\t\t},\n\t\t\tcontainer: document.querySelector( '.my-nav-container' ),\n\t\t}),\n\t]\n);\n\n```\n\n### Styles\n\nYou can import base styles from the library to get started. The base styles include basic styles for the slider and some plugins.\n\n```scss\n@use \"@evermade/overflow-slider/style.css\";\n```\n\nYou can use the CSS variables to override some values easily.\n\nNote that you can easily write styles from scratch if you want to. See source code from `src/overflow-slider.scss` for reference.\n\n## Using in React\n\nOverflow Slider can be used with React. There is no separate core or plugins for React so usage is very similar to vanilla JS. Overflow Slider depends on expanding existing DOM and adding DOM elements so it needs reliable access to these elements.\n\nIn React the way to give this access is `useRef`.\n\n```js\nimport { useRef, useEffect } from 'react';\nimport { OverflowSlider } from '@evermade/overflow-slider';\nimport DragScrollingPlugin from '@evermade/overflow-slider/plugins/drag-scrolling';\nimport ArrowsPlugin from '@evermade/overflow-slider/plugins/arrows';\n\nconst ImageSlider = () =\u003e {\n\tconst sliderElement = useRef(null);\n\tconst sliderControls = useRef(null);\n\n\tuseEffect(() =\u003e {\n\t\tif (!sliderElement.current || !sliderControls.current) {\n\t\t\treturn; \n\t\t}\n\n\t\tconst slider = new OverflowSlider(\n\t\t\tsliderElement.current,\n\t\t\t{\n\t\t\t\temulateScrollSnap: true,\n\t\t\t},\n\t\t\t[\n\t\t\t\tDragScrollingPlugin(),\n\t\t\t\tArrowsPlugin({\n\t\t\t\t\tcontainer: sliderControls.current\n\t\t\t\t}),\n\t\t\t]\n\t\t);\n\t}, []);\n\n\treturn (\n\t\t\u003cdiv className=\"slider-container\"\u003e\n\t\t\t\u003cdiv className=\"overflow-slider\" ref={sliderElement}\u003e\n\t\t\t\t\u003cdiv className=\"overflow-slider__slider-item\"\u003e\u003ch2\u003eSlide 1\u003c/h2\u003e\u003c/div\u003e\n\t\t\t\t\u003cdiv className=\"overflow-slider__slider-item\"\u003e\u003ch2\u003eSlide 2\u003c/h2\u003e\u003c/div\u003e\n\t\t\t\t\u003cdiv className=\"overflow-slider__slider-item\"\u003e\u003ch2\u003eSlide 3\u003c/h2\u003e\u003c/div\u003e\n\t\t\t\u003c/div\u003e\n\t\t\t\u003cdiv className=\"slider-controls\" ref={sliderControls}\u003e\n\t\t\t\u003c/div\u003e\n\t\t\u003c/div\u003e\n\t);\n};\n\nexport default ImageSlider;\n```\n\nNote that Overflow Slider does not have destroy() function. If not having it turns out to be a big issue for React we could add it but that is something affecting all core/plugins and can increase bundle size ~25% as it can be a lot of code.\n\n## Mixins\n\nIf you are using SCSS, you can use these helpers.\n\n```scss\n@use \"@evermade/overflow-slider/mixins\";\n```\n\n### slide-width\n\n```scss\n@mixin os-slide-width($slidesPerView: 3, $gap: var(--slide-gap, 1rem), $containerWidth: var(--slider-container-width, 90vw)) {\n\twidth: calc( ( #{$containerWidth} / #{$slidesPerView} ) - calc( #{$slidesPerView} - 1 ) / #{$slidesPerView} * #{$gap});\n}\n```\n\nSet slide width based on slides per view (more below)\n\n### os-break-out-full-width\n\nMake slider container full width via breaking out of the container that has max-width set.\n\n```scss\n@mixin os-break-out-full-width {\n\tposition: relative;\n\tleft: 50%;\n\twidth: 100vw;\n\tmargin-left: -50vw;\n}\n```\n\n## Slides per view\n\nYou control slides per view in CSS. Set gap between slides via `gap` to slider element. Note that you cannot use percentages (like 33.33%) for width because they are relative to the container and not the viewport.\n\n### A) Slides per view approach\n\nThis is most practical approach and relies on some calculations. Setting target width for slider container is recommended as that makes the calculations more stable as otherwise container width can depend on slides and if slides then depend on container width that can lead some issues.\n\nSetting target width can be done for example referencing another HTML element in page and copying its width:\n\n```js\nconst blockWrapper = document.querySelector( '.block-wrapper' );\nOverflowSlider(\n\tsliderContainer,\n\t{\n\t\ttargetWidth: () =\u003e {\n\t\t\t\treturn (blockWrapper).offsetWidth;\n\t\t},\n\t}\n);\n```\n\nThis creates a `--slider-container-target-width` variable that is now stable.\n\nUse mixin `os-slide-width` \n\n```scss\n.overflow-slider {\n\t--gap: 1.5rem;\n\tgap: var(--gap);\n\t\u003e * {\n\t\t--slides-per-view: 1.5;\n\t\t@include os-slide-width(\n\t\t\tvar(--slides-per-view),\n\t\t\tvar(--gap),\n\t\t\tvar(--slider-container-target-width)\n\t\t);\n\t\t@meadia (min-width: 768px) {\n\t\t\t--slides-per-view: 3;\n\t\t}\n\t}\n}\n```\n\n### B) Fixed width\n\nSet fixed width for slides: `width: 200px;`. Note you can freely change this with media queries.\n\n### C) Relative width\n\nSet relative width for slides: `width: 100vw;`. Note that you cannot use percentages because they are relative to the container and not the viewport.\n\n## Plugins\n\n### DragScrollingPlugin\n\nThis plugin allows you to scroll the slider by dragging with a mouse. This works with items that have links or are links themselves.\n\n```ts\nimport DragScrollingPlugin from '@evermade/overflow-slider/plugins/drag-scrolling';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tDragScrollingPlugin(), // add options here or don't\n\t]\n);\n```\n\nAll options are optional.\n\n```ts\ntype DragScrollingOptions = {\n\tdraggedDistanceThatPreventsClick: number, // default 10, how much user can drag before it's considered a drag and not a click in case of links\n};\n```\n\n### ArrowsPlugin\n\nThis plugin adds previous and next arrows to the slider. You can customize the text, icons and class names.\n\n```ts\nimport ArrowsPlugin from '@evermade/overflow-slider/plugins/arrows';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tArrowsPlugin(), // add options here or don't\n\t]\n);\n```\n\nAll options are optional.\n\n```ts\ntype ArrowsOptions = {\n\ttexts: {\n\t\tbuttonPrevious: string;\n\t\tbuttonNext: string;\n\t},\n\ticons: {\n\t\tprev: string; // SVG or other HTML\n\t\tnext: string; // SVG or other HTML\n\t},\n\tclassNames: {\n\t\tnavContainer: string;\n\t\tprevButton: string;\n\t\tnextButton: string;\n\t},\n\tcontainer: HTMLElement | null, // container for both arrows\n\tcontainerPrev: HTMLElement | null, // container for previous arrow\n\tcontainerNext: HTMLElement | null, // container for next arrow\n\tmovementType: 'view' | 'slide', // default 'view', how much to move when arrow is clicked\n};\n```\n\n### ScrollIndicatorPlugin\n\nThis plugin adds a scroll indicator to the slider. The indicator is a bar that shows how much of the slider is scrolled. Scroll indicator is like a custom scrollbar that is always visible.\n\n```ts\nimport ScrollIndicatorPlugin from '@evermade/overflow-slider/plugins/scroll-indicator';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tScrollIndicatorPlugin(), // add options here or don't\n\t]\n);\n```\n\nAll options are optional.\n\n```ts\ntype ScrollIndicatorOptions = {\n\tclassNames: {\n\t\tscrollIndicator: string;\n\t\tscrollIndicatorBar: string;\n\t\tscrollIndicatorButton: string;\n\t},\n\tcontainer: HTMLElement | null, // container for the scroll indicator\n};\n```\n\n### DotsPlugin\n\nThis plugin adds dots to the slider. Dots are like pagination that shows how many slides there are and which one is active. For usability, scroll indicator is preferable.\n\n```ts\nimport DotsPlugin from '@evermade/overflow-slider/plugins/dots';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tDotsPlugin(), // add options here or don't\n\t]\n);\n```\n\nAll options are optional.\n\n```ts\ntype DotsOptions = {\n\ttype: 'view' | 'slide';\n\ttexts: {\n\t\tdotDescription: string;\n\t},\n\tclassNames: {\n\t\tdotsContainer: string;\n\t\tdotsItem: string;\n\t},\n\tcontainer: HTMLElement | null,\n};\n```\n\n### SkipLinksPlugin\n\nThis plugin adds skip links to the slider for keyboard users. Skip links are links that allow users to skip the whole slider and land after it. This is useful for accessibility.\n\n```ts\nimport SkipLinksPlugin from '@evermade/overflow-slider/plugins/skip-links';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tSkipLinksPlugin(), // add options here or don't\n\t]\n);\n```\n\n### ClassNamesPlugin\n\nAdds CSS classes to each slide based on its visibility inside the slider's target width (or the container width when no target width is supplied). Useful for animating only the slides that are currently in view.\n\n```ts\nimport ClassNamesPlugin from '@evermade/overflow-slider/plugins/classnames';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tClassNamesPlugin({\n\t\t\tfreezeStateOnVisible: true,\n\t\t\tclassNames: {\n\t\t\t\tvisible: 'is-visible',\n\t\t\t\tpartlyVisible: 'is-partly-visible',\n\t\t\t\thidden: 'is-hidden',\n\t\t\t},\n\t\t}),\n\t]\n);\n```\n\nAll options are optional.\n\n```ts\ntype ClassnameOptions = {\n\tclassNames: {\n\t\tvisible: string;\n\t\tpartlyVisible: string;\n\t\thidden: string;\n\t};\n\tfreezeStateOnVisible: boolean; // keep slides in \"visible\" state once they have been fully seen\n};\n```\n\nAll options are optional.\n\n```ts\ntype SkipLinkOptions = {\n\ttexts: {\n\t\tskipList: string;\n\t},\n\tclassNames: {\n\t\tskipLink: string;\n\t\tskipLinkTarget: string;\n\t},\n\tcontainerBefore: HTMLElement | null,\n\tcontainerAfter: HTMLElement | null,\n};\n```\n\n### FullWidthPlugin\n\nThis plugin allows you to make the slider full width but have the start of the sliders aligned to your content width. They are scrollable to the full width but the slides are aligned to the content width for the start and end.\n\n```ts\nimport FullWidthPlugin from '@evermade/overflow-slider/plugins/full-width';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tFullWidthPlugin(), // add options here or don't\n\t]\n);\n```\n\nAll options are optional.\n\n```ts\ntype FullWidthOptions = {\n\ttargetWidth: ( slider: Slider ) =\u003e number,\n\taddMarginBefore: boolean,\n\taddMarginAfter: boolean,\n};\n```\n\nExample of `targetWidth` function:\n\n```ts\nconst sliderElement = document.querySelector( '.slider-container-here' );\nconst sliderWrapper = document.querySelector( '.slider-wrapper' );\nif ( !sliderElement || !sliderWrapper ) {\n\tthrow new Error( 'Slider element or wrapper not found' );\n}\nconst slider = new OverflowSlider(\n\tsliderElement,\n\t{},\n\t[\n\t\tFullWidthPlugin({\n\t\t\ttargetWidth: ( slider ) =\u003e {\n\t\t\t\treturn sliderWrapper.offsetWidth;\n\t\t\t},\n\t\t}),\n\t]\n);\n```\n\n### FadePlugin\n\nThis plugin adds a hint that there are more slides to scroll to. It fades the slides at the start and end of the slider to hint that there are more slides to scroll to.\n\n```ts\nimport FadePlugin from '@evermade/overflow-slider/plugins/fade';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tFadePlugin(), // add options here or don't\n\t]\n);\n```\n\nAll options are optional.\n\n```ts\ntype FadeOptions = {\n\tclassNames: {\n\t\tfadeItem: string;\n\t\tfadeItemStart: string;\n\t\tfadeItemEnd: string;\n\t},\n\tcontainer: HTMLElement | null,\n\tcontainerStart: HTMLElement | null,\n\tcontainerEnd: HTMLElement | null,\n};\n```\n\n### ThumbnailsPlugin\n\nThis plugin adds synchronized thumbnails to the slider. Thumbnails are like dots but they are images of the slides. They are synchronized with the main slider.\n\n```ts\nimport ThumbnailsPlugin from '@evermade/overflow-slider/plugins/thumbnails';\n\nconst slider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n\t{},\n\t[\n\t\tThumbnailsPlugin(), // add options here or don't\n\t]\n);\n```\n\nYou need to set mainSlider reference.\n\n```ts\ntype ThumbnailsOptions = {\n\tmainSlider: Slider,\n}\n```\n\nExample:\n\n```ts\nconst mainSlider = new OverflowSlider(\n\tdocument.querySelector( '.slider-container-here' ),\n);\n\nconst thumbnailsSlider = new OverflowSlider(\n\tdocument.querySelector( '.thumbnails-container-here' ),\n\t{},\n\t[\n\t\tThumbnailsPlugin({\n\t\t\tmainSlider: mainSlider,\n\t\t}),\n\t]\n);\n```\n\n### AutoplayPlugin\n\nThis plugin allows you to automatically scroll the slider. It can be used to create a hero slider that scrolls automatically.\n\nThis includes play/pause button and for users that prefer reduced motion, autoplay plugin will not execute.\n\n```ts\nimport AutoplayPlugin from '@evermade/overflow-slider/plugins/autoplay';\nconst slider = new OverflowSlider(\n document.querySelector( '.slider-container-here' ),\n {},\n [\n\tAutoplayPlugin(), // add options here or don't\n ]\n);\n```\n\nAll options are optional.\n\n```ts\nexport type AutoplayPluginOptions = {\n\tdelayInMs: number;\n\ttexts: {\n\t\tplay: string;\n\t\tpause: string;\n\t};\n\ticons: {\n\t\tplay: string;\n\t\tpause: string;\n\t};\n\tclassNames: {\n\t\tautoplayButton: string;\n\t};\n\tcontainer: HTMLElement | null;\n\tmovementType: 'view' | 'slide';\n\tstopOnHover: boolean;\n\tloop: boolean;\n};\n```\n\n## Known issues\n\n### CSS grids and Overflow Slider\n\nYou can use use Overflow Slider within CSS grid but if you are using `fr` units remember to set them like `minmax(0, 1fr)` instead of just `1fr`. With plain `1fr` the width of columns can be calculated incorrectly by browser.\n\n### CSS scroll-snap can be buggy\n\nIf you are using `scroll-snap-type` CSS property, you might encounter some bugs like browser wants to snap to a slide regardless of margins. It's most reliable when there's only one slide per view.\n\n## Limitations\n\n### Vertical scrolling\n\nThe library is designed to work with horizontal scrolling. Vertical scrolling is not supported at the moment. Maybe some day but it's much rarer use case.\n\n### Infinite scroll\n\nInfinite scroll is not supported and likely never will be. It is not accessible and causes really complex problems as with overflow we are bound to more \"physics\" than transform based sliders and there's no escape of the physics (like visible slides need to represent DOM order).\n\n## Changelog\n\nSee [CHANGELOG.md](./CHANGELOG.md)\n\n## Development\n\nInstall tools `npm install` and build `npm run build` or develop with `npm run watch`.\n\nReleasing new version:\n\n* Update version in `package.json`\n* Commit to master\n* Set tag with version number to git\n* Create new release in GitHub\n* NPM package is automatically published from GitHub\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevermade%2Foverflow-slider","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevermade%2Foverflow-slider","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevermade%2Foverflow-slider/lists"}