Skip to content
Merged

Next #90

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
8b472a1
Replace scrl with a native scroll implementation
hirasso May 31, 2025
4ef7212
Update Documentation
hirasso May 31, 2025
b37a793
Constrain scrolling to the maximum available scroll height
hirasso Jun 3, 2025
7254062
Use `clientHeight` instead of `offsetHeight`
hirasso Jun 5, 2025
4455472
Update packages
daun Jun 6, 2025
1f5aadd
Extract explicit scrollTo method
daun Jun 6, 2025
47dd30b
Recursively scroll nested elements into view
daun Jun 6, 2025
8cfe02e
Revert linting on README.md
hirasso Jun 6, 2025
83f674c
Add swup's `.editorconfig`
hirasso Jun 6, 2025
7a8ea8e
Merge pull request #88 from swup/feat/native-scrolling
hirasso Jun 6, 2025
0a75548
Repeat renaming of default branch to `main` 🤦‍♂️
hirasso Jun 6, 2025
88ef463
Remove incorrect code comment
hirasso Jun 6, 2025
12ccfb3
Formatting
hirasso Jun 6, 2025
5c9a572
Setup e2e and unit tests
hirasso Jun 7, 2025
493510d
Add test workflows
hirasso Jun 7, 2025
b95c46e
Cleanup test fixtures
hirasso Jun 7, 2025
49edaac
Fix test workflows
hirasso Jun 7, 2025
0db20bd
Optimize Readme
hirasso Jun 7, 2025
845e5a9
Remove scrl related stuff from the readme
hirasso Jun 7, 2025
b9d8412
Merge pull request #91 from swup/add-tests
hirasso Jun 7, 2025
d92fb2b
Merge branch 'next' into feat/native-scrolling-details
daun Jun 8, 2025
9c52a46
Pull in library for spec-compliant scrolling into view
daun Jun 8, 2025
c4fe40c
Clean up
daun Jun 8, 2025
bb62b87
Clarify naming between targets and containers
daun Jun 8, 2025
77b187f
Merge pull request #89 from swup/feat/native-scrolling-details
daun Jun 8, 2025
effcd5b
Implement horizontal scroll
daun Jun 8, 2025
b708d0c
Scroll to top left
daun Jun 8, 2025
96caa6c
Support vertical and horizontal offsets
daun Jun 9, 2025
cd52ba2
Ensure scroll position defaults
daun Jun 9, 2025
93d691e
Fixtures WIP
hirasso Jun 9, 2025
fbcca30
Add nested scrolling links
hirasso Jun 9, 2025
7d87bbb
WIP
hirasso Jun 9, 2025
4947dc4
WIP
hirasso Jun 9, 2025
1accd13
Cleanup
hirasso Jun 9, 2025
9ba4951
Move `./tests/e2e/fixtures` to `./playground`
hirasso Jun 9, 2025
d560981
WIP
hirasso Jun 10, 2025
b272d1b
WIP
hirasso Jun 10, 2025
f1f9467
Add `data-swup-scroll-container` attributes for e2e tests
hirasso Jun 10, 2025
bd20bb6
Prepare for scroll preservation tests
hirasso Jun 10, 2025
75bc131
Use an attribute `[data-preserve-scroll]` instead of a class name
hirasso Jun 10, 2025
fa2a05e
Clean up
hirasso Jun 10, 2025
3800449
Remove unnessesary check for empty `scrollTarget`
hirasso Jun 11, 2025
bcf45c8
Set left to zero if the provided offset value is a number
hirasso Jun 11, 2025
25ec9da
Communicate that `scrollTarget` and `scrollContainer` are never undef…
hirasso Jun 11, 2025
729a72f
Simplify playground offset callback
hirasso Jun 11, 2025
de3ab2e
Pass the position to `OffsetCallback`
hirasso Jun 11, 2025
363b3cd
Export the type `OffsetCallback`
hirasso Jun 11, 2025
b631bce
Merge pull request #93 from swup/feat/horizontal-scrolling
hirasso Jun 12, 2025
bb5959a
Untrack dynamic astro stuff
hirasso Jun 27, 2025
71d7014
Update Astro
hirasso Jun 27, 2025
eb3a52d
playground: use a custom callback for `getAnchorElement`
hirasso Jun 27, 2025
c16c79f
playground: fix title
hirasso Jun 27, 2025
daa5eb0
Fix PlayWright UI mode
hirasso Jun 27, 2025
35f7a1d
Git-Ignore test results
hirasso Jun 27, 2025
a904475
Cleanup basic hello world test
hirasso Jun 27, 2025
ebd100f
Add tests for anchor scrolling
hirasso Jun 27, 2025
a117eea
Add tests for resetting and restoring the scroll position
hirasso Jun 27, 2025
fa7af12
Add tests for `options.offset`
hirasso Jun 27, 2025
26bbcfa
Test the option `animateScroll`
hirasso Jun 27, 2025
912d7d7
Add test for `offset` as an object
hirasso Jun 27, 2025
34333ab
Uninstall jsdom
hirasso Jun 27, 2025
506781c
Add test for `getOffset` to always return an object
hirasso Jun 27, 2025
44be347
Optimize code comments
hirasso Jun 27, 2025
12716c2
Use `new Function` instead of `eval` for function deserialization
hirasso Jun 27, 2025
735d659
Extract serialize and unserialize
hirasso Jun 27, 2025
40b56c4
Ignore badges on swup docs
hirasso Jun 28, 2025
1c17fb0
Merge pull request #97 from swup/feat/add-tests
hirasso Jun 29, 2025
eb47df4
Apply scroll position in scroll:apply hook
daun Jul 27, 2025
8b7beec
Freeze left scroll on cancel
daun Jul 27, 2025
6d52cbf
Update readme
daun Jul 27, 2025
c7d7653
Switch to scrollFunction option
daun Aug 2, 2025
df1cc20
Update readme
daun Aug 2, 2025
7ae122c
Test custom scroll function call
daun Aug 2, 2025
dd5fb32
Unify readme spelling
daun Aug 4, 2025
851da95
Resolve body to window event target
daun Aug 4, 2025
19e1aa0
Update GSAP example
daun Aug 4, 2025
bb8d333
Fix comment spelling
daun Aug 4, 2025
905f293
Remove unneccessary vite config
daun Aug 4, 2025
9a8fef9
Merge pull request #99 from swup/feat/scroll-apply-hook
daun Aug 4, 2025
eca572b
Prepare CHANGELOG for v4
hirasso Aug 4, 2025
a563b84
Update version in CDN link
hirasso Aug 4, 2025
2ca6c17
Add test for exposing `scrollTo` on the swup instance
hirasso Aug 4, 2025
559d84e
Remove unnecessary boilerplate from unit tests
hirasso Aug 4, 2025
7c3af9d
Update CHANGELOG
hirasso Aug 4, 2025
6527485
Fix typo
hirasso Aug 4, 2025
df7113c
Merge pull request #100 from swup/feat/prepare-v4
hirasso Aug 4, 2025
1d43d5a
Add `src` to the files downloaded from npm
hirasso Aug 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
root = true

[*]
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 100

[*.{js,mjs,ts}]
indent_style = tab
indent_size = 4

[*.{json,md,yaml,yml}]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
33 changes: 33 additions & 0 deletions .github/workflows/e2e-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: E2E tests

on:
push:
branches: [main, next]
pull_request:
workflow_dispatch:

jobs:
run-tests:
name: E2E tests
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3
with:
node-version: 18

- run: npm ci
- run: npm run build
- run: npm run test:e2e:install

- name: Run tests
run: npm run test:e2e

- uses: daun/playwright-report-summary@v2
with:
report-file: playwright-results.json
4 changes: 2 additions & 2 deletions .github/workflows/redeploy-docs.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
name: Redeploy Docs
on:
push:
branches: [master]
branches: [main]

jobs:
redeploy-docs:
uses: swup/.github/.github/workflows/redeploy-docs.yml@master
uses: swup/.github/.github/workflows/redeploy-docs.yml@main
secrets: inherit
28 changes: 28 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Unit tests

on:
push:
branches: [main, next]
pull_request:
workflow_dispatch:

jobs:
run-tests:
name: Run unit tests
runs-on: ubuntu-latest
timeout-minutes: 5

steps:
- name: Check out repo
uses: actions/checkout@v3

- name: Set up node
uses: actions/setup-node@v3
with:
node-version: 18

- run: npm ci
- run: npm run build

- name: Run tests
run: npm run test:unit
2 changes: 1 addition & 1 deletion .github/workflows/version-update.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
run: npm --no-git-tag-version version ${{ inputs.segment }}
- uses: peter-evans/create-pull-request@v4
with:
base: 'master'
base: 'main'
branch: 'version/automated'
title: 'Update package version (automated)'
commit-message: 'Update package version'
Expand Down
20 changes: 19 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,25 @@ wiki-images files
wiki-wishlist
*.sublime-project
*.sublime-workspace
.editorconfig
.idea
dist
/plugins

# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*

# Astro
/playground/dist
/playground/.astro

# Testing tools and outputs
/tests/e2e/reports/
/tests/e2e/results/
/playwright/.cache/
/playwright-report/
/coverage
.nyc_output
report.json
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## [4.0.0] - 2025-08-04

- Drop dependency on [gmrchk/scrl](https://github.com/gmrchk/scrl) in favor of a native scroll implementation
- Support nested scroll containers
- Support scrolling both axis (top, left)
- New option `scrollFunction` to customize the scroll implementation
- Added unit and end-to-end tests

## [3.3.2] - 2024-02-05

- Pass temporary visit into scroll hooks
Expand Down Expand Up @@ -80,6 +88,7 @@

- Initial release

[4.0.0]: https://github.com/swup/scroll-plugin/releases/tag/4.0.0
[3.3.2]: https://github.com/swup/scroll-plugin/releases/tag/3.3.2
[3.3.1]: https://github.com/swup/scroll-plugin/releases/tag/3.3.1
[3.3.0]: https://github.com/swup/scroll-plugin/releases/tag/3.3.0
Expand Down
109 changes: 56 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# Swup Scroll plugin
# Swup Scroll Plugin

<!-- swup-docs-ignore-start -->

[![Unit Tests](https://img.shields.io/github/actions/workflow/status/swup/scroll-plugin/unit-tests.yml?branch=next&label=unit%20tests)](https://github.com/swup/scroll-plugin/actions/workflows/unit-tests.yml)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hirasso We should also think of a way of hiding the readme badges from the docs site. They look a bit off in that context. Maybe an html comment type thing?

<!-- swup-docs-hide-start -->
(badge)
(badge)
<!-- swup-docs-hide-end -->

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually like them: image

But not hugely important :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like them too, but on GitHub 👨🏻‍💻 In the docs, learning that playwright and vitest are passing before learning what the plugin does is a bit distracting, I think?

Copy link
Member Author

@hirasso hirasso Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd don't have a strong preference - might be my inside view... fine for me either way :)

[![E2E Tests](https://img.shields.io/github/actions/workflow/status/swup/scroll-plugin/e2e-tests.yml?branch=next&label=e2e%20tests)](https://github.com/swup/scroll-plugin/actions/workflows/e2e-tests.yml)
[![License](https://img.shields.io/github/license/swup/scroll-plugin.svg)](https://github.com/swup/scroll-plugin/blob/main/LICENSE)

<!-- swup-docs-ignore-end -->

A [swup](https://swup.js.org) plugin for customizable smooth scrolling.

- Enables acceleration-based smooth scrolling
- Animates scroll position between page visits
- Animates scrolling to anchors
- Enable smooth scrolling
- Animate scroll position between page visits
- Animate scrolling to anchors
- Define a custom offset for scroll positions
- Handle nested scroll containers
- Emulate scroll target selector

## Installation
Expand All @@ -23,7 +32,7 @@ import SwupScrollPlugin from '@swup/scroll-plugin';
Or include the minified production file from a CDN:

```html
<script src="https://unpkg.com/@swup/scroll-plugin@3"></script>
<script src="https://unpkg.com/@swup/scroll-plugin@4"></script>
```

## Usage
Expand Down Expand Up @@ -98,10 +107,6 @@ For finer control, you can pass an object:
}
```

### scrollFriction and scrollAcceleration

The animation behavior of the scroll animation can be adjusted by setting `scrollFriction` and `scrollAcceleration`.

### getAnchorElement

Customize how the scroll target is found on the page. Defaults to standard browser behavior (`#id` first, `a[name]` second).
Expand Down Expand Up @@ -139,18 +144,23 @@ To highlight the current target element, use the `data-swup-scroll-target` attri

### Offset

Offset to substract from the final scroll position, to account for fixed headers. Can be either a number or a function that returns the offset.
Offset to substract from the final scroll position, to account for fixed headers. Can be either a
static number or a function that returns a value based on the scroll target. To apply differing
offsets for vertical and horizontal scrolling, return an object with `top` and `left` properties.

```javascript
{
// Number: fixed offset in px
offset: 30,

// Object: fixed vertical and horizontal offset in px
offset: { top: 30, left: 10 },

// Function: calculate offset before scrolling
offset: () => document.querySelector('#header').offsetHeight,

// The scroll target element is passed into the function
offset: target => target.offsetHeight * 2,
// The scroll target and container are passed into the function
offset: (scrollTarget, scrollContainer) => target.offsetHeight * 2,
}
```

Expand Down Expand Up @@ -190,13 +200,12 @@ new SwupScrollPlugin({
samePageWithHash: true,
samePage: true
},
scrollFriction: 0.3,
scrollAcceleration: 0.04,
getAnchorElement: null,
markScrollTarget: false,
offset: 0,
scrollContainers: `[data-swup-scroll-container]`,
shouldResetScrollPosition: (link) => true
shouldResetScrollPosition: (link) => true,
scrollFunction: undefined
});
```

Expand All @@ -219,9 +228,15 @@ swup.hooks.on('scroll:start', () => console.log('Swup started scrolling'));
swup.hooks.on('scroll:end', () => console.log('Swup finished scrolling'));
```

## Overwriting `swup.scrollTo`
## Custom scroll function

You can overwrite the scroll function with your own implementation by passing it in as the
`scrollFunction` option. This way, you gain full control over how you animate your scroll positions.
Below is an example using [GSAP's](https://greensock.com/docs/v3/)
[ScrollToPlugin](https://greensock.com/docs/v3/Plugins/ScrollToPlugin).

You can overwrite the scroll function with your own implementation. This way, you can gain full control over how you animate your scroll positions. Here's an example using [GSAP's](https://greensock.com/docs/v3/) [ScrollToPlugin](https://greensock.com/docs/v3/Plugins/ScrollToPlugin):
Note that you are responsible for calling the `start` and `end` functions passed to the scroll
function to let swup correctly trigger the `scroll:start` and `scroll:end` hooks.

```js

Expand All @@ -232,41 +247,29 @@ import { gsap } from 'gsap';
import ScrollToPlugin from 'gsap/ScrollToPlugin';
gsap.registerPlugin(ScrollToPlugin);

const swup = new Swup({
plugins: [new SwupScrollPlugin()]
});

/**
* Overwrite swup's scrollTo function
* Use GSAP ScrollToPlugin for animated scrolling
* @see https://greensock.com/docs/v3/Plugins/ScrollToPlugin
*/
swup.scrollTo = (offsetY, animate = true) => {
if (!animate) {
swup.hooks.callSync('scroll:start', undefined);
window.scrollTo(0, offsetY);
swup.hooks.callSync('scroll:end', undefined);
return;
}

/**
* Use GSAP ScrollToPlugin for animated scrolling
* @see https://greensock.com/docs/v3/Plugins/ScrollToPlugin
*/
gsap.to(window, {
duration: 0.8,
scrollTo: offsetY,
ease: 'power4.inOut',
autoKill: true,
onStart: () => {
swup.hooks.callSync('scroll:start', undefined);
},
onComplete: () => {
swup.hooks.callSync('scroll:end', undefined);
},
onAutoKill: () => {
swup.hooks.callSync('scroll:end', undefined);
},
});

};

```

new Swup({
plugins: [
new SwupScrollPlugin({
scrollFunction: (el, top, left, animate, start, end) => {
gsap.to(el, {
duration: animate ? 0.6 : 0,
ease: "power4.out",
scrollTo: {
y: top,
x: left,
autoKill: window.matchMedia("(hover: hover)").matches,
onAutoKill: () => end(),
},
onStart: () => start(),
onComplete: () => end(),
});
},
}),
]
});
```
Loading
Loading