# Inertia.js
Inertia.js is a modern framework that allows you to build single-page applications (SPAs) using classic server-side routing and controllers. It eliminates the need for a separate API by allowing your server-side framework (Laravel, Rails, etc.) to render pages as JavaScript components (React, Vue, or Svelte) while maintaining the benefits of server-side routing, controllers, and middleware.
The library provides a seamless bridge between server-side and client-side code, offering features like automatic page transitions, form handling with validation, prefetching, polling, infinite scroll, and deferred props loading. It supports React, Vue 3, and Svelte adapters, each providing framework-specific components and hooks that integrate naturally with the respective ecosystem.
## Core API
### createInertiaApp - Application Bootstrap
The `createInertiaApp` function initializes an Inertia application, setting up component resolution, page rendering, and optional progress indicators. It handles both client-side rendering (CSR) and server-side rendering (SSR) configurations.
```tsx
// React CSR Setup (main.tsx)
import { createInertiaApp } from '@inertiajs/react'
import { createRoot } from 'react-dom/client'
createInertiaApp({
resolve: (name) => {
const pages = import.meta.glob('./Pages/**/*.tsx', { eager: true })
return pages[`./Pages/${name}.tsx`]
},
setup({ el, App, props }) {
createRoot(el).render()
},
progress: {
delay: 250,
color: '#29d',
includeCSS: true,
showSpinner: false,
},
defaults: {
form: {
recentlySuccessfulDuration: 2000,
},
prefetch: {
cacheFor: '30s',
hoverDelay: 75,
},
},
})
// React SSR Setup (ssr.tsx)
import { createInertiaApp } from '@inertiajs/react'
import { renderToString } from 'react-dom/server'
export default function render(page) {
return createInertiaApp({
page,
render: renderToString,
resolve: (name) => {
const pages = import.meta.glob('./Pages/**/*.tsx', { eager: true })
return pages[`./Pages/${name}.tsx`]
},
setup({ App, props }) {
return
},
})
}
```
### router - Navigation and Visits
The `router` object provides methods for programmatic navigation, including `visit`, `get`, `post`, `put`, `patch`, `delete`, `reload`, and `prefetch`. It manages page transitions, history, and request lifecycle events.
```tsx
import { router } from '@inertiajs/react'
// Basic navigation
router.visit('/users', {
method: 'get',
data: { search: 'john' },
preserveState: true,
preserveScroll: true,
only: ['users'], // Partial reload - only fetch 'users' prop
except: ['notifications'], // Exclude specific props
replace: true, // Replace history entry
headers: { 'X-Custom-Header': 'value' },
onBefore: (visit) => confirm('Navigate away?'),
onStart: (visit) => console.log('Starting...'),
onProgress: (progress) => console.log(`${progress.percentage}%`),
onSuccess: (page) => console.log('Success!', page),
onError: (errors) => console.error('Errors:', errors),
onCancel: () => console.log('Cancelled'),
onFinish: (visit) => console.log('Finished'),
})
// HTTP method shortcuts
router.get('/users', { page: 1 })
router.post('/users', { name: 'John', email: 'john@example.com' })
router.put('/users/1', { name: 'John Updated' })
router.patch('/users/1', { status: 'active' })
router.delete('/users/1')
// Reload current page with specific props
router.reload({ only: ['notifications'] })
// Prefetch a page for faster navigation
router.prefetch('/dashboard', {}, { cacheFor: '5m', cacheTags: ['dashboard'] })
// Flush prefetch cache
router.flush('/dashboard')
router.flushAll()
router.flushByCacheTags(['dashboard'])
// Cancel in-flight requests
router.cancelAll({ async: true, prefetch: true, sync: true })
// History management
router.remember({ scroll: 100 }, 'scroll-position')
const saved = router.restore('scroll-position')
router.clearHistory()
// Client-side state manipulation
router.replace({ props: (current) => ({ ...current, count: current.count + 1 }) })
router.push({ url: '/new-url', props: { data: 'value' } })
router.replaceProp('user.name', 'New Name')
router.appendToProp('items', newItem)
router.prependToProp('items', newItem)
// Flash messages
router.flash('success', 'Operation completed!')
router.flash({ success: 'Saved!', error: null })
// Global event listeners
const removeListener = router.on('navigate', (event) => {
console.log('Navigated to:', event.detail.page.url)
})
// Later: removeListener()
// Polling
const poll = router.poll(5000, { only: ['notifications'] }, { keepAlive: false })
poll.stop()
poll.start()
```
## React Components
### Link - Client-Side Navigation
The `Link` component creates links that perform client-side navigation without full page reloads. It supports prefetching, preserve options, and all standard anchor attributes.
```tsx
import { Link } from '@inertiajs/react'
function Navigation() {
return (
)
}
```
### useForm - Form State Management
The `useForm` hook provides comprehensive form state management with validation, error handling, progress tracking, and submission. It supports both standard Inertia forms and precognitive (real-time) validation.
```tsx
import { useForm } from '@inertiajs/react'
function CreateUserForm() {
const form = useForm({
name: '',
email: '',
password: '',
avatar: null as File | null,
roles: [] as string[],
})
function handleSubmit(e: React.FormEvent) {
e.preventDefault()
form.post('/users', {
onSuccess: () => form.reset(),
onError: (errors) => console.log('Validation errors:', errors),
forceFormData: true, // Force FormData for file uploads
})
}
return (
)
}
// With remember key (persists form state across page visits)
function RememberedForm() {
const form = useForm('create-user-form', {
name: '',
email: '',
})
// Exclude sensitive fields from being remembered
form.dontRemember('password')
return
}
// With precognitive (real-time) validation
function PrecognitiveForm() {
const form = useForm('post', '/users', {
name: '',
email: '',
})
.withPrecognition('post', '/users')
.setValidationTimeout(500)
.validateFiles()
return (
)
}
// Using transform to modify data before submission
function TransformExample() {
const form = useForm({ date: new Date() })
form.transform((data) => ({
...data,
date: data.date.toISOString(),
}))
return
}
```
### Form - Declarative Form Component
The `Form` component provides a declarative way to handle forms with automatic data collection from native form elements, built-in validation, and submission handling.
```tsx
import { Form, useFormContext } from '@inertiajs/react'
function ContactForm() {
return (
)
}
// Access form context from child components
function SubmitButton() {
const form = useFormContext()
return (
)
}
// With custom transform and callbacks
function AdvancedForm() {
return (
)
}
```
### Head - Document Head Management
The `Head` component manages the document's `` section, allowing you to set titles, meta tags, and other head elements from any component in your application.
```tsx
import { Head } from '@inertiajs/react'
function UserProfile({ user }) {
return (
<>
{user.name} - Profile
{user.name}
{/* ... */}
>
)
}
// Simple title shorthand
function SimplePage() {
return (
<>
Dashboard content
>
)
}
// With head-key for deduplication
function Layout({ children }) {
return (
<>
{children}
>
)
}
// Child can override parent's head-key
function DarkPage() {
return (
<>
Dark themed page
>
)
}
```
### usePage - Access Page Props
The `usePage` hook provides access to the current page's props, component name, URL, and version information.
```tsx
import { usePage } from '@inertiajs/react'
interface PageProps {
auth: {
user: { id: number; name: string; email: string } | null
}
flash: {
success?: string
error?: string
}
}
function Layout({ children }) {
const { props, url, component } = usePage()
return (
{props.flash.success && (
{props.flash.success}
)}
{props.flash.error && (
{props.flash.error}
)}
{children}
)
}
```
### Deferred - Lazy Loading Props
The `Deferred` component displays a fallback while waiting for deferred props to load from the server. This enables loading non-critical data after the initial page render.
```tsx
import { Deferred } from '@inertiajs/react'
function Dashboard({ user }) {
return (
Welcome, {user.name}
{/* Analytics data loads after initial render */}
}>
{/* Multiple deferred props */}
}
>
{/* With render function */}
Loading...
}>
{() => }
)
}
// Server-side (Laravel example):
// return Inertia::render('Dashboard', [
// 'user' => $user,
// 'analytics' => Inertia::defer(fn () => $this->getAnalytics()),
// 'recentOrders' => Inertia::defer(fn () => $this->getOrders()),
// ]);
```
### WhenVisible - Load Data on Visibility
The `WhenVisible` component loads data when an element becomes visible in the viewport, perfect for lazy-loading content below the fold.
```tsx
import { WhenVisible } from '@inertiajs/react'
function ProductPage({ product }) {
return (
{/* Load reviews when scrolled into view */}
}
buffer={200} // Start loading 200px before visible
>
{/* With custom reload params */}
}
>
{/* Always reload when visible (for live data) */}
Checking stock...}
>
{({ fetching }) => (
)}
{/* Custom wrapper element */}
)
}
```
### InfiniteScroll - Automatic Pagination
The `InfiniteScroll` component provides automatic or manual infinite scrolling for paginated data, handling loading states and scroll position preservation.
```tsx
import { InfiniteScroll } from '@inertiajs/react'
function PostsFeed({ posts }) {
return (
{({ loading, loadingNext, loadingPrevious }) => (
<>
{posts.data.map((post) => (
))}
{loading && }
>
)}
)
}
// Manual loading with custom buttons
function ManualPagination({ items }) {
return (
hasMore && (
)
}
next={({ fetch, hasMore, loading }) =>
hasMore && (
)
}
loading={}
>
{items.data.map((item) => (
))}
)
}
// Auto-load initially, then manual after 3 pages
function HybridScroll({ comments }) {
return (
manualMode && (
)
}
>
{comments.data.map((comment) => (
))}
)
}
// Chat-style reverse scrolling
function ChatMessages({ messages }) {
const scrollRef = useRef(null)
return (
{messages.data.map((message) => (
))}
)
}
```
## React Hooks
### usePoll - Automatic Data Refresh
The `usePoll` hook sets up automatic polling to refresh page data at specified intervals.
```tsx
import { usePoll } from '@inertiajs/react'
function NotificationBell({ notifications }) {
// Poll every 30 seconds
const { stop, start } = usePoll(30000, {
only: ['notifications'],
})
// Stop polling when component unmounts (automatic)
// Manually control polling:
const handleFocus = () => start()
const handleBlur = () => stop()
return (
)
}
```
### useRemember - Persistent State
The `useRemember` hook persists state across page visits using the browser's history state.
```tsx
import { useRemember } from '@inertiajs/react'
function FilterableList() {
// State persists when navigating away and back
const [filters, setFilters] = useRemember({
search: '',
sortBy: 'created_at',
sortDir: 'desc',
}, 'list-filters')
return (