isInViewport
Checks if a DOM element is in the viewport.
1/**
2 * Checks if a DOM element is in the viewport.
3 *
4 * @param el - The DOM element to check.
5 * @param partiallyVisible - If true, returns true if any part is visible.
6 * @returns True if the element is in the viewport.
7 */
8export function isInViewport(el: Element, partiallyVisible = true): boolean {
9 const rect = el.getBoundingClientRect();
10
11 if (partiallyVisible) {
12 return (
13 rect.bottom > 0 &&
14 rect.right > 0 &&
15 rect.top < window.innerHeight &&
16 rect.left < window.innerWidth
17 );
18 } else {
19 return (
20 rect.top >= 0 &&
21 rect.left >= 0 &&
22 rect.bottom <= window.innerHeight &&
23 rect.right <= window.innerWidth
24 );
25 }
26}
Supports Partial and Full Visibility Checks
The
partiallyVisible
flag allows flexible usage depending on whether any or all of the element needs to be in view.No External Dependencies
Uses native DOM APIs like
getBoundingClientRect
, keeping the utility lightweight and portable.High Performance
Avoids complex intersection observers or polling, making it suitable for simple and fast viewport checks.
Versatile for Layout Decisions
Provides foundational logic for lazy loading, animations, and scroll-triggered interactions.
Tests | Examples
1function createElementWithRect(rect: Partial<DOMRect>): Element {
2 return {
3 getBoundingClientRect: () =>
4 ({
5 top: rect.top ?? 0,
6 bottom: rect.bottom ?? 0,
7 left: rect.left ?? 0,
8 right: rect.right ?? 0,
9 } as DOMRect),
10 } as unknown as Element;
11}
12
13Object.defineProperty(window, 'innerWidth', { value: 1024 });
14Object.defineProperty(window, 'innerHeight', { value: 768 });
15
16test('returns true if element is fully visible', () => {
17 const el = createElementWithRect({
18 top: 100,
19 bottom: 200,
20 left: 100,
21 right: 200,
22 });
23 expect(isInViewport(el, false)).toBe(true);
24});
25
26test('returns false if element is outside viewport', () => {
27 const el = createElementWithRect({
28 top: 800,
29 bottom: 900,
30 left: 100,
31 right: 200,
32 });
33 expect(isInViewport(el)).toBe(false);
34});
35
36test('returns true if element is partially visible', () => {
37 const el = createElementWithRect({
38 top: -50,
39 bottom: 50,
40 left: 100,
41 right: 200,
42 });
43 expect(isInViewport(el)).toBe(true);
44});
45
46test('returns false if element is not even partially visible', () => {
47 const el = createElementWithRect({
48 top: -200,
49 bottom: -100,
50 left: 100,
51 right: 200,
52 });
53 expect(isInViewport(el)).toBe(false);
54});
Common Use Cases
Lazy Loading Images or Components
Trigger loading when a component enters the viewport to optimize performance and reduce initial load time.
Scroll-Triggered Animations
Apply animations or transitions only when the element is visible to the user.
Infinite Scrolling
Detect when the user has reached the end of a list or section to load more content.
Sticky Headers or UI Visibility
Determine if a section is currently visible to toggle sticky headers or navigation indicators.
Accessibility or Focus Management
Ensure key content is within view before shifting focus or reading content aloud.