0
# Navigation & Scroll
1
2
Navigation helpers and scroll management including pagination logic, smooth scrolling, scroll spy functionality, and headroom patterns.
3
4
## Capabilities
5
6
### usePagination
7
8
Pagination logic with range calculation and navigation controls.
9
10
```typescript { .api }
11
/**
12
* Pagination logic with range calculation
13
* @param options - Pagination configuration
14
* @returns Object with pagination state and controls
15
*/
16
function usePagination(options: UsePaginationOptions): UsePaginationReturnValue;
17
18
const DOTS = 'dots';
19
20
interface UsePaginationOptions {
21
initialPage?: number;
22
page?: number;
23
total: number;
24
siblings?: number;
25
boundaries?: number;
26
onChange?: (page: number) => void;
27
}
28
29
interface UsePaginationReturnValue {
30
range: (number | 'dots')[];
31
active: number;
32
setPage: (page: number) => void;
33
next: () => void;
34
previous: () => void;
35
first: () => void;
36
last: () => void;
37
}
38
```
39
40
**Usage Examples:**
41
42
```typescript
43
import { usePagination } from "@mantine/hooks";
44
45
function DataTable({ totalItems }: { totalItems: number }) {
46
const [currentPage, setCurrentPage] = useState(1);
47
const itemsPerPage = 10;
48
const totalPages = Math.ceil(totalItems / itemsPerPage);
49
50
const pagination = usePagination({
51
total: totalPages,
52
page: currentPage,
53
onChange: setCurrentPage,
54
siblings: 1,
55
boundaries: 1,
56
});
57
58
return (
59
<div>
60
<div>{/* Table content */}</div>
61
62
<div>
63
<button onClick={pagination.first} disabled={pagination.active === 1}>
64
First
65
</button>
66
<button onClick={pagination.previous} disabled={pagination.active === 1}>
67
Previous
68
</button>
69
70
{pagination.range.map((page, index) => (
71
<button
72
key={index}
73
onClick={() => typeof page === 'number' && pagination.setPage(page)}
74
disabled={page === 'dots'}
75
className={page === pagination.active ? 'active' : ''}
76
>
77
{page === 'dots' ? '...' : page}
78
</button>
79
))}
80
81
<button onClick={pagination.next} disabled={pagination.active === totalPages}>
82
Next
83
</button>
84
<button onClick={pagination.last} disabled={pagination.active === totalPages}>
85
Last
86
</button>
87
</div>
88
</div>
89
);
90
}
91
```
92
93
### useScrollIntoView
94
95
Smooth scroll into view with animation and cancellation support.
96
97
```typescript { .api }
98
/**
99
* Smooth scroll into view with animation
100
* @param options - Scroll configuration
101
* @returns Object with refs and scroll controls
102
*/
103
function useScrollIntoView<T extends HTMLElement = any>(
104
options?: UseScrollIntoViewOptions
105
): UseScrollIntoViewReturnValue<T>;
106
107
interface UseScrollIntoViewOptions {
108
duration?: number;
109
axis?: 'x' | 'y';
110
easing?: (t: number) => number;
111
offset?: number;
112
cancelable?: boolean;
113
isList?: boolean;
114
onScrollFinish?: () => void;
115
}
116
117
interface UseScrollIntoViewReturnValue<T extends HTMLElement = any> {
118
scrollableRef: React.RefCallback<T | null>;
119
targetRef: React.RefCallback<HTMLElement | null>;
120
scrollIntoView: (alignment?: ScrollLogicalPosition) => void;
121
cancel: () => void;
122
}
123
```
124
125
**Usage Examples:**
126
127
```typescript
128
import { useScrollIntoView } from "@mantine/hooks";
129
130
function ScrollableList({ items, activeId }: Props) {
131
const { scrollableRef, targetRef, scrollIntoView } = useScrollIntoView<HTMLDivElement>({
132
duration: 500,
133
offset: 60,
134
onScrollFinish: () => console.log('Scrolled to target'),
135
});
136
137
useEffect(() => {
138
if (activeId) {
139
scrollIntoView({ block: 'center' });
140
}
141
}, [activeId, scrollIntoView]);
142
143
return (
144
<div ref={scrollableRef} style={{ height: '400px', overflow: 'auto' }}>
145
{items.map(item => (
146
<div
147
key={item.id}
148
ref={item.id === activeId ? targetRef : undefined}
149
className={item.id === activeId ? 'active' : ''}
150
>
151
{item.title}
152
</div>
153
))}
154
</div>
155
);
156
}
157
```
158
159
### useScrollSpy
160
161
Track active section during scroll for table of contents navigation.
162
163
```typescript { .api }
164
/**
165
* Track active section during scroll
166
* @param selectors - Array of CSS selectors to track
167
* @param options - Scroll spy configuration
168
* @returns Tuple with root ref, active index, and heading data
169
*/
170
function useScrollSpy<T extends HTMLElement = any>(
171
selectors: string[],
172
options?: UseScrollSpyOptions<T>
173
): UseScrollSpyReturnType;
174
175
interface UseScrollSpyOptions<T extends HTMLElement = any> {
176
root?: T;
177
rootMargin?: string;
178
threshold?: number | number[];
179
}
180
181
interface UseScrollSpyHeadingData {
182
id: string;
183
level: number;
184
element: HTMLElement;
185
}
186
187
type UseScrollSpyReturnType = [
188
React.RefCallback<HTMLElement | null>, // rootRef
189
number, // activeIndex
190
UseScrollSpyHeadingData[] // headings
191
];
192
```
193
194
### useHeadroom
195
196
Hide/show header based on scroll direction for better UX.
197
198
```typescript { .api }
199
/**
200
* Hide/show header based on scroll direction
201
* @param options - Headroom configuration
202
* @returns Boolean indicating if header should be pinned
203
*/
204
function useHeadroom(options?: UseHeadroomOptions): boolean;
205
206
interface UseHeadroomOptions {
207
fixedAt?: number;
208
onPin?: () => void;
209
onRelease?: () => void;
210
}
211
```
212
213
**Usage Examples:**
214
215
```typescript
216
import { useHeadroom } from "@mantine/hooks";
217
218
function Header() {
219
const pinned = useHeadroom({ fixedAt: 120 });
220
221
return (
222
<header
223
style={{
224
position: 'fixed',
225
top: 0,
226
left: 0,
227
right: 0,
228
transform: pinned ? 'translateY(0)' : 'translateY(-100%)',
229
transition: 'transform 0.3s ease',
230
zIndex: 1000,
231
}}
232
>
233
<nav>Navigation content</nav>
234
</header>
235
);
236
}
237
```