Templates¶
Configure the root template for Inertia applications.
See also
Official Inertia.js docs: Server-Side Setup
Root Template¶
The root template is the HTML shell for your Inertia application. It’s rendered on initial page loads with page data embedded.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/static/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title inertia>react-inertia</title>
{{ vite_hmr() }}
{{ vite('resources/main.tsx') }}
</head>
<body>
<div id="app"></div>
<script type="application/json" id="app_page" data-page="app">{{ inertia | safe }}</script>
</body>
</html>
Key features:
<title inertia>- Enables dynamic title updates via Inertia’s<Head>component<script type="application/json" id="app_page" data-page="app">- Script-element bootstrap payload foruse_script_element=True{{ inertia | safe }}- JSON-encoded page payload (use| safeto prevent escaping){{ vite_hmr() }}and{{ vite() }}- Vite asset injection
Template Helpers¶
These helpers are automatically available in your templates:
Helper |
Description |
|---|---|
|
Include Vite assets (JS, CSS) |
|
HMR client script (dev mode) |
|
JSON-encoded page payload for |
|
Hidden CSRF input field |
|
Raw CSRF token value |
Script Element Bootstrap¶
When InertiaConfig(use_script_element=True) is enabled, keep the app root element empty and
emit the JSON payload in a matching script element:
<div id="app"></div>
<script type="application/json" id="app_page" data-page="app">{{ inertia | safe }}</script>
For current Inertia v2 clients, your browser entry must opt into the same transport:
createInertiaApp({
defaults: {
future: {
useScriptElementForInitialPage: true,
},
},
// resolve/setup...
})
If InertiaConfig(ssr=True) is also enabled, mirror the same
defaults.future.useScriptElementForInitialPage setting in resources/ssr.tsx or
resources/ssr.ts so the Node SSR entry and the browser entry hydrate from the same payload.
Note
This explicit defaults.future setup matches the stable Inertia v2.3+ client docs. In the
official v3 upgrade guide, the future namespace is removed, so keep this example version-scoped.
Classic data-page Bootstrap¶
The {{ inertia | safe }} helper can also be used directly with the older data-page attribute:
{
"component": "Dashboard",
"props": {"user": {"name": "Alice"}},
"url": "/dashboard",
"version": "abc123"
}
Important
Always use | safe with the inertia helper to prevent HTML escaping:
<div id="app" data-page='{{ inertia | safe }}'></div>
Without | safe, special characters in props will be escaped, breaking JSON parsing.
Use this attribute form only when you are not using use_script_element=True.
Dynamic Titles¶
Add the inertia attribute to <title> for dynamic title support:
<title inertia>Default Title</title>
Then update titles from your components using Inertia’s <Head> component:
import { Head } from '@inertiajs/react';
function Dashboard() {
return (
<>
<Head title="Dashboard - My App" />
{/* page content */}
</>
);
}
SPA Mode (No Templates)¶
In SPA mode, you don’t need Jinja templates. The index.html from
your Vite project is used directly:
ViteConfig(
inertia=InertiaConfig(),
)
Your index.html (in resource_dir):
<!DOCTYPE html>
<html>
<head>
<script type="module" src="/resources/main.ts"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
Litestar-Vite automatically injects data-page and CSRF token.
Customizing the App Selector¶
Change the root element selector:
InertiaConfig(
app_selector="#root", # Default: "#app"
)
<div id="root"></div>
<script type="application/json" id="app_page" data-page="root">{{ inertia | safe }}</script>
Multiple Templates¶
Use different templates for different sections:
@get("/admin/dashboard", component="Admin/Dashboard")
async def admin_dashboard() -> InertiaResponse:
return InertiaResponse(
content={...},
template_name="admin.html", # Override default
)
Template Organization¶
Recommended structure:
templates/
├── index.html # Main Inertia template
├── admin.html # Admin section template
└── partials/
└── head.html # Shared head content
Using template inheritance:
<!DOCTYPE html>
<html>
<head>
{% block head %}
{{ vite('resources/main.ts') }}
{{ vite_hmr() }}
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
{% extends "base.html" %}
{% block body %}
<div id="app" data-page='{{ inertia | safe }}'></div>
{% endblock %}
See Also¶
Configuration - Template configuration options
Install and Configure - Vite asset helpers