wire:intersect
The official Livewire UI kit
Build polished Livewire apps faster.
Explore Flux ProLivewire's wire:intersect directive allows you to execute an action when an element enters or leaves the viewport. This is useful for lazy loading content, triggering analytics, or creating scroll-based interactions.
Basic usage
The simplest form runs an action when an element becomes visible:
<div wire:intersect="loadMore"> <!-- Content loads when scrolled into view --></div>
When the element enters the viewport, the loadMore action will be called on your component.
Enter and leave events
You can specify whether to run the action on enter, leave, or both:
<!-- Runs when entering viewport (default) --><div wire:intersect="trackView">...</div> <!-- Runs when entering viewport (explicit) --><div wire:intersect:enter="trackView">...</div> <!-- Runs when leaving viewport --><div wire:intersect:leave="pauseVideo">...</div>
Visibility modifiers
Control how much of the element needs to be visible before triggering:
<!-- Trigger when any part is visible (default) --><div wire:intersect="load">...</div> <!-- Trigger when half is visible --><div wire:intersect.half="load">...</div> <!-- Trigger when fully visible --><div wire:intersect.full="load">...</div> <!-- Trigger at custom threshold (0-100) --><div wire:intersect.threshold.25="load">...</div>
Margin
Add a margin around the viewport to trigger the action before/after the element enters:
<!-- Trigger 200px before entering viewport --><div wire:intersect.margin.200px="loadMore">...</div> <!-- Use percentage-based margin --><div wire:intersect.margin.10%="loadMore">...</div> <!-- Different margins for each side (top, right, bottom, left) --><div wire:intersect.margin.10%.25px.25px.25px="loadMore">...</div>
Fire once
Use the .once modifier to ensure the action only fires on the first intersection:
<div wire:intersect.once="trackImpression"> <!-- Action only fires once, even if scrolled past multiple times --></div>
This is particularly useful for analytics or tracking when you only want to record the first time a user sees something.
Require continuous visibility
Use .dwell when an element must remain visible before the action runs. The default dwell time is 250 milliseconds:
<div wire:intersect.dwell="trackView">...</div>
Add a duration modifier to choose a different interval:
<!-- Run after 500 milliseconds of continuous visibility --><div wire:intersect.dwell.500ms="trackView">...</div>
The dwell timer resets if the element stops meeting its visibility threshold or the page moves to the background. It starts again when the element becomes eligible in a visible page.
For wire:intersect:leave, the dwell interval instead begins after visibility falls below the configured threshold:
<div wire:intersect:leave.half.dwell.500ms="pauseVideo">...</div>
Combine .dwell with a visibility threshold and .once to record a qualified impression:
<div wire:intersect.once.half.dwell.1000ms="trackImpression">...</div>
Combining modifiers
You can combine multiple modifiers to create precise behaviors:
<!-- Load when half visible, only once, with 100px margin --><div wire:intersect.once.half.margin.100px="loadSection"> <!-- ... --></div>
Common use cases
Infinite scroll
<?php use Livewire\Component; new class extends Component { public $page = 1; public $posts = []; public function mount() { $this->loadPosts(); } public function loadPosts() { $newPosts = Post::latest() ->skip(($this->page - 1) * 10) ->take(10) ->get(); $this->posts = array_merge($this->posts, $newPosts->toArray()); $this->page++; }};?> <div> @foreach ($posts as $post) <div>{{ $post['title'] }}</div> @endforeach <div wire:intersect="loadPosts"> Loading more posts... </div></div>
Lazy loading images
<?php use Livewire\Component; new class extends Component { public $imageLoaded = false; public function loadImage() { $this->imageLoaded = true; }};?> <div> @if ($imageLoaded) <img src="/path/to/image.jpg" alt="Product"> @else <div wire:intersect.once="loadImage" class="bg-gray-200 h-64"> <!-- Placeholder --> </div> @endif</div>
Tracking visibility
<div wire:intersect:enter.once="trackView" wire:intersect:leave="trackLeave"> <!-- Track when users view and leave this content --></div>
Comparison with Alpine's x-intersect
If you're familiar with Alpine.js, wire:intersect works similarly to x-intersect but triggers Livewire actions instead of Alpine expressions. The modifiers and behavior are designed to feel familiar to Alpine users.
Reference
wire:intersect="action"wire:intersect:enter="action"wire:intersect:leave="action"
Modifiers
| Modifier | Description |
|---|---|
.once |
Only fire the action on the first intersection |
.dwell.[duration] |
Require continuous visibility before firing (defaults to 250ms) |
.half |
Trigger when half of the element is visible |
.full |
Trigger when the entire element is visible |
.threshold.[0-100] |
Trigger at a custom visibility threshold percentage |
.margin.[value] |
Add margin around the viewport (e.g., .margin.200px, .margin.10%) |
.parent |
Observe visibility within the element's parent instead of the browser viewport |
.renderless |
Run the action without rendering the component |
.async |
Run the action in a parallel request |
.preserve-scroll |
Preserve the page's scroll position through the action |