A VuePress plugin that automatically activates sidebar links when the page scrolls
npx @tessl/cli install tessl/npm-vuepress--plugin-active-header-links@1.9.00
# VuePress Active Header Links Plugin
1
2
The VuePress Active Header Links Plugin automatically activates sidebar links when the page scrolls, providing visual feedback to users about their current position in the document. It monitors scroll events and determines which header anchor is currently visible, then updates the browser's hash and highlights the corresponding sidebar link.
3
4
## Package Information
5
6
- **Package Name**: @vuepress/plugin-active-header-links
7
- **Package Type**: npm
8
- **Language**: JavaScript
9
- **Installation**: `npm install @vuepress/plugin-active-header-links`
10
11
## Core Imports
12
13
```javascript
14
// In VuePress config file
15
module.exports = {
16
plugins: ['@vuepress/active-header-links']
17
}
18
```
19
20
**Plugin Development Dependencies:**
21
22
```javascript
23
const { path } = require('@vuepress/shared-utils');
24
import debounce from 'lodash.debounce';
25
```
26
27
## Basic Usage
28
29
```javascript
30
// Basic plugin registration
31
module.exports = {
32
plugins: ['@vuepress/active-header-links']
33
}
34
35
// With custom configuration options
36
module.exports = {
37
plugins: ['@vuepress/active-header-links', {
38
sidebarLinkSelector: '.sidebar-link',
39
headerAnchorSelector: '.header-anchor'
40
}]
41
}
42
```
43
44
## Capabilities
45
46
### Plugin Factory Function
47
48
Creates and configures the VuePress plugin with optional settings for CSS selectors.
49
50
```javascript { .api }
51
/**
52
* Main plugin export - factory function that creates the active header links plugin
53
* @param {PluginOptions} options - Configuration options for the plugin (defaults to empty object)
54
* @returns {PluginObject} VuePress plugin object
55
*/
56
const { path } = require('@vuepress/shared-utils');
57
58
module.exports = (options = {}) => ({
59
clientRootMixin: path.resolve(__dirname, 'clientRootMixin.js'),
60
define: {
61
AHL_SIDEBAR_LINK_SELECTOR: options.sidebarLinkSelector || '.sidebar-link',
62
AHL_HEADER_ANCHOR_SELECTOR: options.headerAnchorSelector || '.header-anchor'
63
}
64
});
65
66
interface PluginOptions {
67
/** CSS selector for sidebar links (default: '.sidebar-link') */
68
sidebarLinkSelector?: string;
69
/** CSS selector for header anchors (default: '.header-anchor') */
70
headerAnchorSelector?: string;
71
}
72
73
interface PluginObject {
74
/** Path to client-side mixin file */
75
clientRootMixin: string;
76
/** Global constants for client-side usage */
77
define: {
78
AHL_SIDEBAR_LINK_SELECTOR: string;
79
AHL_HEADER_ANCHOR_SELECTOR: string;
80
};
81
}
82
83
// TypeScript type support from @vuepress/types
84
type Plugin<T extends PluginOptions = PluginOptions> =
85
(options: T) => PluginObject;
86
```
87
88
**Usage Examples:**
89
90
```javascript
91
// Default configuration
92
module.exports = {
93
plugins: ['@vuepress/active-header-links']
94
}
95
96
// Custom selectors for different theme structure
97
module.exports = {
98
plugins: ['@vuepress/active-header-links', {
99
sidebarLinkSelector: '.custom-sidebar-link',
100
headerAnchorSelector: '.custom-header-anchor'
101
}]
102
}
103
104
// Using full plugin name
105
module.exports = {
106
plugins: [
107
['@vuepress/plugin-active-header-links', {
108
sidebarLinkSelector: '.nav-link',
109
headerAnchorSelector: '.anchor-link'
110
}]
111
]
112
}
113
```
114
115
### Client-Side Behavior
116
117
The plugin automatically injects client-side functionality that provides smooth scrolling behavior and active link highlighting.
118
119
**Client-Side Implementation:**
120
The plugin injects a Vue.js mixin (`clientRootMixin.js`) that provides:
121
122
```javascript { .api }
123
// Vue.js mixin pattern
124
import debounce from 'lodash.debounce';
125
126
export default {
127
mounted() {
128
window.addEventListener('scroll', this.onScroll);
129
},
130
methods: {
131
onScroll: debounce(function() {
132
this.setActiveHash();
133
}, 300),
134
setActiveHash() {
135
// Active header detection logic
136
}
137
},
138
beforeDestroy() {
139
window.removeEventListener('scroll', this.onScroll);
140
}
141
};
142
```
143
144
**Scroll Event Handling:**
145
- Listens to window scroll events with 300ms debouncing for performance
146
- Determines which header anchor is currently visible in the viewport
147
- Updates browser hash to reflect the current section
148
- Integrates seamlessly with VuePress routing system
149
150
**Active Link Detection Algorithm:**
151
- Finds all sidebar links that correspond to header anchors on the page
152
- Calculates scroll position using cross-browser compatible methods
153
- Determines active anchor based on scroll position and viewport
154
- Handles edge cases like being at the bottom of the page
155
156
**Hash Management:**
157
- Updates `$route.hash` to maintain navigation state
158
- Temporarily disables VuePress scroll behavior during hash updates
159
- Uses `decodeURIComponent` for proper Unicode support in anchors
160
- Preserves existing hash when user is at bottom of page
161
- Uses `this.$vuepress.$set('disableScrollBehavior', true)` for scroll management
162
- Integrates with Vue router using `this.$router.replace()`
163
164
## Configuration Options
165
166
### sidebarLinkSelector
167
168
CSS selector for sidebar navigation links.
169
170
```javascript { .api }
171
sidebarLinkSelector?: string = '.sidebar-link'
172
```
173
174
This selector is used to find sidebar links that should be activated based on the current scroll position. The plugin will match these links with corresponding header anchors on the page.
175
176
### headerAnchorSelector
177
178
CSS selector for header anchor elements.
179
180
```javascript { .api }
181
headerAnchorSelector?: string = '.header-anchor'
182
```
183
184
This selector identifies the anchor elements within headers that are used for navigation. These anchors must have `hash` properties that correspond to sidebar link destinations.
185
186
## Integration Requirements
187
188
**Dependencies:**
189
- `@vuepress/shared-utils`: Used for path resolution utilities
190
- `lodash.debounce`: Used for scroll event debouncing (300ms delay)
191
192
**VuePress Plugin System:**
193
- Must be registered in the VuePress configuration file
194
- Integrates with VuePress's client-side plugin system
195
- Uses VuePress's `clientRootMixin` mechanism for client-side functionality
196
197
**DOM Structure Requirements:**
198
- Sidebar links must have `hash` properties matching header anchors
199
- Header anchors must be positioned within elements that have `offsetTop` properties
200
- Elements must be accessible via `document.querySelectorAll()`
201
202
**Browser Compatibility:**
203
- Supports modern browsers with ES6+ features
204
- Uses standard DOM APIs and scroll event handling
205
- Compatible with VuePress's Vue.js version requirements
206
207
## Error Handling
208
209
The plugin gracefully handles common scenarios:
210
211
- **Missing Elements**: If selectors don't match any elements, the plugin continues to work without errors
212
- **Scroll Position Edge Cases**: Properly handles being at the top or bottom of the page
213
- **Hash Conflicts**: Resolves conflicts when multiple anchors could be considered active
214
- **Route Changes**: Cleans up event listeners when navigating between pages