Fine-Tuning Client-Side Navigation with Inertia.js Visit Options
Learn how to use Inertia.js visit options like preserveState, preserveScroll, and partial reloads to eliminate full page refreshes and build fluid, SPA-like user experiences.
03 Feb 2026, 02:55 UTC

The \"Full Page Reload\" Friction
In a traditional multi-page application, every interaction—a filter change, a pagination click, or a form submission—triggers a full browser refresh. This wipes the local component state, resets the scroll position to the top, and creates a jarring visual flash. While Single Page Applications (SPAs) solve this, they often require building a separate REST or GraphQL API to handle data fetching.
Inertia.js bridges this gap by intercepting clicks and submissions, converting them into XHR requests. The server returns a JSON object containing the component name and the data (props) instead of a full HTML document. However, the default behavior of an Inertia visit is to reset the page state. To build truly fluid interfaces, you need to control exactly what is preserved during these transitions.
Controlling State and Scroll Position
The visit method (and its shorthand helpers like get, post, and put) accepts an options object that dictates how the browser handles the transition. Two of the most critical options are preserveState and preserveScroll.
preserveState
By default, Inertia destroys the current component instance and creates a new one when navigating. Setting preserveState: true tells Inertia to keep the current component instance alive. This is essential for maintaining local UI state that isn't mirrored in the database, such as the text currently typed into a search input or the open/closed state of a dropdown menu.
preserveScroll
Standard navigation resets the window scroll to the top. When implementing \"Load More\" buttons or inline filters, this is disruptive. preserveScroll: true prevents the browser from jumping, keeping the user exactly where they were while the data updates in the background.
Optimizing Data Transfer with Partial Reloads
A common performance bottleneck in Inertia apps is fetching the entire page dataset when only one small piece of information changes. The only option enables Partial Reloads.
When you pass an array of keys to only, Inertia sends a special header to the server. The server-side controller can then conditionally load only those specific props, reducing database load and shrinking the JSON payload size. This is particularly useful for heavy tables or complex dashboards where you only want to refresh a specific metric or a filtered list.
Worked Example: A Filterable Data Table
Imagine a user interface with a search input and a list of records. We want the search input to remain focused and the scroll position to stay put while the results update.
// Example using Vue 3 and Inertia.js
import { router } from '@inertiajs/vue3';
const handleSearch = (event) => {
router.get('/users',
{ search: event.target.value },
{
// Keeps the search input focused and local state intact
preserveState: true,
// Prevents the page from jumping to the top on every keystroke
preserveScroll: true,
// Only requests the 'users' prop from the server, ignoring others
only: ['users'],
}
);
};
Execution Details
- Where to run: This code runs in the client-side JavaScript component.
- Permissions: No special permissions required beyond standard browser XHR access.
- Expected Check: Open the browser DevTools Network tab. You should see a request with the
X-Inertia: trueheader. The response should be a JSON object containing only theuserskey within thepropsobject, rather than the full page data.
Trade-offs and Limitations
While preserveState creates a seamless experience, it introduces the risk of stale UI state. If the server-side data changes in a way that should logically reset the client-side state (e.g., a permission change that should hide a button), preserveState may keep the old UI visible until a hard refresh occurs.
Additionally, Inertia relies on the server to render the initial page. If the server fails to provide the initial HTML shell, the client-side routing cannot bootstrap, and the visit method will fail to execute as the application will not have loaded.
Verifying the Result
- Interact with the element triggering the
visit. - Observe the URL: It should update to reflect the new state/query parameters.
- Check the UI: If
preserveStateis active, local input fields should not clear. IfpreserveScrollis active, the page should not jump. - Inspect the Network tab: Confirm the response is JSON and, if using
only, verify that unnecessary props are omitted from the payload.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.