Skip to content

Commit 2256d46

Browse files
committed
edit README
1 parent a05eadf commit 2256d46

File tree

1 file changed

+80
-58
lines changed

1 file changed

+80
-58
lines changed

README.md

Lines changed: 80 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,14 @@
33

44
# Vue Use Active Scroll
55

6-
[Live Demo](https://vue-use-active-scroll.netlify.app/)
7-
8-
<br />
9-
10-
**Examples**
11-
12-
[With Template Refs](https://stackblitz.com/edit/vitejs-vite-sywzg8?file=src%252Fpages%252FIndex.vue) - [Nuxt Content Nested TOC](https://stackblitz.com/edit/github-oh85gq?file=components%2FSidebar.vue) - [Markup from a CMS](https://stackblitz.com/edit/vitejs-vite-9feebm?file=src%252Fpages%252FIndex.vue)
6+
[Live Demo](https://vue-use-active-scroll.netlify.app/) — Examples: [With Template Refs](https://stackblitz.com/edit/vitejs-vite-sywzg8?file=src%252Fpages%252FIndex.vue) - [Nuxt Content Nested TOC](https://stackblitz.com/edit/github-oh85gq?file=components%2FSidebar.vue)
137

148
<br />
159

1610
## Why?
1711

1812
The [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) is a great API.
19-
But it may not be the one-size-fits-all solution to highlight nav/sidebar links. Most likely because you want to:
13+
But it may not be the one-size-fits-all solution to highlight TOC/sidebar links as it makes hard if not impossible to:
2014

2115
- Highlight any clicked link even if it will never intersect
2216
- Always highlight first/last link once reached the top/bottom of the page
@@ -28,11 +22,9 @@ But it may not be the one-size-fits-all solution to highlight nav/sidebar links.
2822

2923
### Do you really need it?
3024

31-
If you don't care about the above gotchas, then no, please **don't use this package** because it adds a couple of KBs to your JS bundle that you don't need.
32-
33-
You can achieve a good result with the Intersection Observer API as well. The [Astro docs TOC](https://github.com/withastro/docs/blob/main/src/components/RightSidebar/TableOfContents.tsx) is a great example in just 30 lines of code.
25+
If you and your users don't care about the above gotchas, then no, please **don't use this package** because it adds a couple of unnecessary KBs to your bundle.
3426

35-
Moreover, this package is meant for highlighting links in vertical sidebars and may be overkill for other use cases lik menu header links.
27+
You can achieve an acceptable result with the Intersection Observer API as well. Alternatively, you can build an accurate scroll observer that acts similar to this package by looking at the [SvelteKit Website's TOC](https://github.com/sveltejs/site-kit/blob/master/packages/site-kit/src/lib/docs/DocsOnThisPage.svelte) source code in 100-150 lines of code.
3628

3729
<br />
3830

@@ -56,13 +48,9 @@ Moreover, this package is meant for highlighting links in vertical sidebars and
5648

5749
<br />
5850

59-
## Requirements
51+
## Getting Started
6052

61-
If scrolling to anchors, Vue Router (RouterLink / NuxtLink) is required.
62-
63-
<br />
64-
65-
## Installation
53+
### Installation
6654

6755
```bash
6856
pnpm add vue-use-active-scroll
@@ -72,6 +60,45 @@ pnpm add vue-use-active-scroll
7260
# bun add vue-use-active-scroll
7361
```
7462

63+
> [!WARNING]
64+
> If you plan to use this package with scroll to anchors (e.g. docs TOC) and you're not using Nuxt, Vue Router is required and `scrollBehavior` must be configured in the router instance by following the next section.
65+
66+
### Configure `scrollBehavior`
67+
68+
> [!NOTE]
69+
> If using **Nuxt**, you can skip to the [next section](#set-css-scroll-behavior) as it's already taken care for you by the framework.
70+
71+
As explained in the above warning, Vue Router needs to be configured in order to scroll to anchors.
72+
73+
```js
74+
const router = createRouter({
75+
// Add this method 👇
76+
scrollBehavior(to) {
77+
if (to.hash) {
78+
return {
79+
el: to.hash,
80+
}
81+
}
82+
},
83+
})
84+
```
85+
86+
The above is the bare minimum required to get started and it will make sure that when clicking on a `RouterLink` that has an anchor in its `href` the window will scroll to that element.
87+
88+
> Later on, see the [Vue Router Section](#vue-router---additional-configurations) for additional configurations (container scroll, fixed header offsets, etc.).
89+
90+
### Set CSS `scroll-behavior`
91+
92+
Somewhere in your global CSS, add the following rule to enable smooth scrolling:
93+
94+
```css
95+
html {
96+
scroll-behavior: smooth; /* or 'auto' if you prefer instant scrolling */
97+
}
98+
```
99+
100+
> Later on, see the [Scroll Behavior Section](#configure-scrollbehavior) for additional scroll configurations or on how to use JS-based scrolling.
101+
75102
<br />
76103

77104
## Usage
@@ -90,10 +117,6 @@ The composable returns an object with properties to react to the active link and
90117
const { setActive, activeId, activeIndex /*, ... */ } = useActiveScroll(targets)
91118
```
92119

93-
> :warning: In case you setup Vue Router from scratch (e.g. Vite SPA), please make sure that you have configured [scroll behavior](#vue-router---scroll-to-and-from-hash) in your router instance.
94-
>
95-
> This is not required if using Nuxt as it's already configured by the framework.
96-
97120
---
98121

99122
### Scenario 1 - Template refs (preferred)
@@ -184,7 +207,10 @@ const { setActive, activeId } = useActiveScroll(ids)
184207
</template>
185208
```
186209

187-
### Scenario 3 - Incoming HTML
210+
<details>
211+
<summary>
212+
<h3>Scenario 3 - Incoming HTML</h3>
213+
</summary>
188214

189215
In this case, you must query the DOM in an `onMounted` hook or a watcher in order to get the targets.
190216

@@ -252,10 +278,14 @@ const { setActive, activeId } = useActiveScroll(targets)
252278
</template>
253279
```
254280

281+
</details>
282+
255283
<br />
256284

257285
## Customization
258286

287+
### `useActiveScroll` options
288+
259289
`useActiveScroll` accepts an optional configuration object as last argument:
260290

261291
```js
@@ -275,7 +305,7 @@ const { activeId, setActive } = useActiveScroll(targets, {
275305
| overlayHeight | `number` | 0 | Height in pixels of any **CSS fixed** content that overlaps the top of your scrolling area (e.g. fixed header). Must be paired with a CSS [scroll-margin-top](#setting-scroll-margin-top-for-fixed-headers) rule. |
276306
| minWidth | `number` | 0 | Whether to toggle listeners and functionalities within a specific width. Useful if hiding the sidebar using `display: none`. |
277307

278-
### Return object
308+
#### Return object
279309

280310
| Name | Type | Description |
281311
| ----------- | -------------------------------------------- | ------------------------------------------------------------------------------------ |
@@ -285,13 +315,11 @@ const { activeId, setActive } = useActiveScroll(targets, {
285315
| activeId | `Ref<string>` | Active target ID |
286316
| activeIndex | `Ref<number>` | Index of the active target in offset order, `0` for the first target and so on. |
287317

288-
<br />
289-
290-
## Defining scroll behavior
318+
### Scroll behavior and types
291319

292-
You're free to choose between CSS (smooth or auto), [scrollIntoView](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) or even a library like [animated-scroll-to](https://github.com/Stanko/animated-scroll-to).
320+
You're free to choose between CSS _scroll-behavior_ (smooth or auto), [scrollIntoView](https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView) or even a JS library like [animated-scroll-to](https://github.com/Stanko/animated-scroll-to).
293321

294-
### CSS scroll-behavior (recommended)
322+
#### CSS (recommended)
295323

296324
- Content scrolled by the window:
297325

@@ -309,7 +337,7 @@ html {
309337
}
310338
```
311339

312-
### Custom JS scroll
340+
<details><summary><h4>JS-based scroll</h4></summary>
313341

314342
```vue
315343
<script setup>
@@ -342,15 +370,13 @@ function scrollTo(event, id) {
342370
</template>
343371
```
344372

345-
<br />
346-
347-
## Vue Router - Scroll to and from anchors
373+
</details>
348374

349-
> :warning: If using Nuxt, Vue Router is already configured to scroll to and from anchors on page load or back/forward navigation. **So you don't need to do follow the steps below**. Otherwise rules must be defined manually.
375+
### Vue Router - Additional Configurations
350376

351-
### Scrolling to anchors
377+
#### Scrolling to anchors inside a container
352378

353-
For content scrolled by the window, simply return the target element. To scroll to a target scrolled by a container, use _scrollIntoView_ method.
379+
To scroll to a target inside of a container, use _scrollIntoView_ method and pass the target's ID.
354380

355381
```js
356382
const router = createRouter({
@@ -376,7 +402,7 @@ const router = createRouter({
376402
377403
> :bulb: There's no need need to set overlayHeight if using `scrollIntoView` as the method is aware of target's `scroll-margin-top` property.
378404
379-
### Scrolling from anchor back to the top of the page
405+
#### Scrolling from anchors back to the page root
380406

381407
To navigate back to the top of the same page (e.g. clicking on browser's back button from hash to the page root), use the _scroll_ method for containers and return _top_ for content scrolled by the window.
382408

@@ -400,11 +426,11 @@ const router = createRouter({
400426
})
401427
```
402428

403-
### Preventing hash from being pushed
429+
#### Preventing the hash from being pushed
404430

405431
You may noticed that when clicking on a link, a new entry is added to the history. When navigating back, the page will scroll to the previous target and so on.
406432

407-
If you don't like that, choose to replace instead of pushing the hash:
433+
To disable this, choose to replace instead of pushing the hash:
408434

409435
```vue
410436
<template>
@@ -420,11 +446,23 @@ If you don't like that, choose to replace instead of pushing the hash:
420446
</template>
421447
```
422448

423-
<br />
449+
### Setting scroll-margin-top for fixed headers
424450

425-
## Server-side rendering
451+
You might noticed that if you have a fixed header and defined an `overlayHeight`, once clicked to scroll, the target may be underneath the header. In this case, add `scroll-margin-top` to your targets:
426452

427-
Since `useActiveScroll` won't kick in until the page is hydrated, if you're using Nuxt, you might want to render the first link as active if on the server.
453+
```js
454+
useActiveScroll(targets, { overlayHeight: 100 })
455+
```
456+
457+
```css
458+
.target {
459+
scroll-margin-top: 100px;
460+
}
461+
```
462+
463+
### Server-side rendering
464+
465+
Since `useActiveScroll` won't kick in until the page is hydrated, you probably want to render the first link as active on the server.
428466

429467
```vue
430468
<script setup>
@@ -450,22 +488,6 @@ onMounted(() => (isSSR.value = false))
450488

451489
<br />
452490

453-
## Setting scroll-margin-top for fixed headers
454-
455-
You might noticed that if you have a fixed header and defined an `overlayHeight`, once clicked to scroll, the target may be underneath the header. You must add `scroll-margin-top` to your targets:
456-
457-
```js
458-
useActiveScroll(targets, { overlayHeight: 100 })
459-
```
460-
461-
```css
462-
.target {
463-
scroll-margin-top: 100px;
464-
}
465-
```
466-
467-
<br />
468-
469491
## License
470492

471493
MIT

0 commit comments

Comments
 (0)