Laravel Inertia

48 Min | December 27, 2024

The demand for more efficient and seamless user experiences has increased as web development evolves. Traditional multi-page applications (MPAs) are slowly being replaced by faster, more dynamic, and responsive single-page applications (SPAs). Popular platforms like Facebook, Twitter, and YouTube have adopted SPAs, which provide users with a smoother and more interactive browsing experience. However, building SPAs with server-side frameworks like Laravel can be difficult, mainly when keeping the code clean and manageable.

This is where Inertia.js comes in, offering a game-changing solution for Laravel developers. Inertia allows you to create modern, SPA-like experiences without completely changing your existing Laravel application. It acts as a bridge between the backend and frontend, enabling you to use powerful JavaScript frameworks like Vue.js or React while still maintaining server-side logic in Laravel.

In this article, we’ll explore the benefits of using Inertia with Laravel, explain how it simplifies the development process, and guide you through getting started with Laravel Inertia. By the end, you’ll understand how to use Inertia to build dynamic, modern web applications without the complexity of traditional SPA development.

Why Use Inertia with Laravel?

Inertia.js provides a powerful solution for combining modern frontend technologies with Laravel. It allows developers to create dynamic, interactive user interfaces using Laravel’s strong backend features. Using Inertia with Laravel, developers can streamline their workflow, combining the best of both worlds in a simple approach that makes development easier and improves the user experience.

Inertia simplifies web development by letting Laravel manage the server-side logic, while frontend frameworks like Vue.js or React handle the client-side actions. This removes the need for a separate API layer, as Inertia enables smooth backend and frontend communication. As a result, developers can work faster, maintain their code more efficiently, and create a more cohesive application.

Another significant advantage is the improved developer experience. Inertia lets developers stay in a familiar Laravel environment while enjoying modern frontend features without the hassle of managing separate codebases. The process is much simpler than traditional SPA development, which often involves complex API interactions. Inertia also boosts performance by improving page load times and navigation, reducing the need for full page reloads while supporting Laravel’s server-side rendering capabilities.

Additionally, Inertia’s smooth integration between the backend and frontend makes it easier to transition from traditional server-rendered applications to dynamic, client-side experiences. Developers no longer need to deal with different frameworks or complicated API structures. With shared code between the backend and frontend, Inertia simplifies the application logic and data flow, making it easier to maintain and scale. This leads to a more efficient development process and a better user experience.

What Problem Does Laravel Inertia Solve?

Laravel Inertia solves key challenges in web development by connecting server-side and client-side development. It makes it easier to create dynamic web applications and eliminates the need for a separate API layer.

Using Inertia with Laravel provides a simple way to build modern web applications. It combines Laravel’s server-side power with the dynamic, interactive features of frontend frameworks like Vue.js or React. This integration lets developers use Laravel’s strong backend and a more dynamic, SPA-like frontend experience without entirely switching to SPA architecture.

Inertia also makes it easier to build interactive web applications by allowing developers to create dynamic user interfaces while keeping the backend logic centralized within Laravel. This approach avoids the complexity of traditional multi-page applications or entirely separate SPAs, making it simpler to create responsive and dynamic applications without managing complex frontend-backend separation.

Moreover, Inertia removes the need to create and maintain separate API endpoints for communication between the frontend and backend. With Inertia, Laravel controllers manage both the backend logic and the data sent to the frontend, making development smoother and the codebase more consistent. This reduces the complexity of managing separate API layers, simplifying the overall architecture and improving maintainability.

How Does Inertia Work?

Inertia.js changes the way the frontend and backend interact in web applications. It allows developers to create modern, dynamic user interfaces while maintaining Laravel’s traditional server-driven architecture. As a bridge between the backend and frontend, Inertia makes it easy to connect them without the complexity of building a complete Single-Page Application (SPA).

Inertia lets Laravel manage the server-side logic while using frontend frameworks like Vue.js or React to render the user interface. This approach allows developers to create SPA-like experiences without needing an entirely separate API layer. Instead of rendering entire pages on the server and sending them to the browser, Inertia only returns the necessary data to update the page. This keeps the architecture simple, efficient, and well-integrated, making it easier to build dynamic applications.

Instead of traditional full-page reloads, Inertia uses dynamic data transfers between the client and server. When a user clicks a link or submits a form, Inertia sends an AJAX request (using XHR or Fetch API) to the backend. Laravel controllers handle the request and return the required data rather than reloading a whole page. The client-side Inertia JavaScript then updates only the relevant parts of the page, providing a faster and smoother user experience.

Inertia also handles state and reactivity by letting the frontend framework manage page updates based on the data returned from the backend. The frontend keeps track of the state, and when the data changes, it re-renders only the necessary components. Inertia makes the application behave like a SPA by managing routing on the client side and updating the page dynamically, all while keeping the backend in control of the data and logic. This approach makes it easier to create interactive user interfaces without complex client-side state and routing management.

Getting Started with Laravel Inertia

In this section’ll walk you through integrating Inertia.js into a Laravel application. By the end, you’ll have a fully functional blog app with Laravel as the backend, Vue.js for the frontend, and Tailwind CSS for styling. Let’s get started!

Prerequisites

Before starting, you should have a basic understanding of:

  • Laravel Basics: You should know how to install Laravel, set up a database, and work with migrations, controllers, routes, and models.
  • Vue.js Basics: You should be familiar with installing Vue.js, component structure, and basic form handling.

Step 1: Install Core Elements

First, set up the essential components of your blog application. Either create a new Laravel project or navigate to an existing one.

Create Blade Components

Create a Blade component for the homepage of your blog in /resources/views/index.blade.php:

<!DOCTYPE html>

<html lang=”{{ str_replace(‘_’, ‘-‘, app()->getLocale()) }}”>

  <head>

    <meta charset=”utf-8″ />

    <meta name=”viewport” content=”width=device-width, initial-scale=1″ />

    <title>Devrims Blog</title>

  </head>

  <body>

    <header>

      <h1>Devrims Blog</h1>

    </header>

    <main>

      <h2>Read our latest articles</h2>

      <section>

        <article>

          <div>

            <img src=”/images/Devrims-logo.png” alt=”Article thumbnail” />

          </div>

          <h3>Title for the blog</h3>

          <p></p>

          <a href=”#”>Read more</a>

        </article>

      </section>

    </main>

    <footer>

      <h2>Join our Newsletter</h2>

      <input type=”email” />

    </footer>

  </body>

</html>

Next, create another Blade component for a single article view at /resources/views/show.blade.php:

<!DOCTYPE html>

<html lang=”{{ str_replace(‘_’, ‘-‘, app()->getLocale()) }}”>

  <head>

    <meta charset=”utf-8″ />

    <meta name=”viewport” content=”width=device-width, initial-scale=1″ />

    <title>Devrims Blog</title>

  </head>

  <body>

    <main>

      <article>

        <div>

          <img src=”/images/Devrims-logo.png” alt=”Article thumbnail” />

        </div>

        <h1>Title for the blog</h1>

        <p>Article content goes here</p>

      </article>

    </main>

    <footer>

      <h2>Join our Newsletter</h2>

      <input type=”email” />

    </footer>

  </body>

</html>

Set Up Database

Create a new MySQL database called Devrims_blog and update the .env file in your Laravel project with the following connection settings:

DB_CONNECTION=mysql

DB_HOST=127.0.0.1

DB_PORT=3306

DB_DATABASE=Devrims_blog

DB_USERNAME=root

DB_PASSWORD=

Create the Article Model

Create a model for the Article entity at app/Models/Article.php:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;

class Article extends Model

{

    use HasFactory;

    protected $fillable = [‘title’, ‘excerpt’, ‘body’];

}

Run Migrations

Create a migration file for the articles table:

<?php

use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;

return new class extends Migration

{

    public function up()

    {

        Schema::create(‘articles’, function (Blueprint $table) {

            $table->id();

            $table->string(‘title’);

            $table->text(‘excerpt’);

            $table->text(‘body’);

            $table->timestamps();

        });

    }

    public function down()

    {

        Schema::dropIfExists(‘articles’);

    }

};

Run the migrations with the following:

php artisan migrate

Create a Factory for Demo Articles

Create a factory to generate demo articles at database/factories/ArticleFactory.php:

<?php

namespace Database\Factories;

use Illuminate\Database\Eloquent\Factories\Factory;

class ArticleFactory extends Factory

{

    public function definition()

    {

        return [

            ‘title’ => $this->faker->sentence(6),

            ‘excerpt’ => $this->faker->paragraph(4),

            ‘body’ => $this->faker->paragraph(15),

        ];

    }

}

Now that your basic blog and articles are stored in the database let’s integrate Inertia.js.

Step 2: Install Inertia.js

Integrating Inertia.js involves the server-side (Laravel) setup and the client-side (Vue.js) setup.

Server-Side Setup

  1. Install the Inertia server-side package via Composer:

composer require inertiajs/inertia-laravel

  1. Create a Blade template to load the Inertia app and other assets (CSS and JS). In /resources/views/app.blade.php, add:

<!DOCTYPE html>

<html lang=”{{ str_replace(‘_’, ‘-‘, app()->getLocale()) }}”>

  <head>

    <meta charset=”utf-8″ />

    <meta name=”viewport” content=”width=device-width, initial-scale=1″ />

    <title inertia>{{ config(‘app.name’, ‘Laravel’) }}</title>

    <!– Scripts –>

    @vite(‘resources/js/app.js’) @inertiaHead

  </head>

  <body class=”font-sans antialiased”>

    @inertia

  </body>

</html>

  1. Install the Inertia middleware:

php artisan inertia:middleware

  1. Add the middleware to the web group in /app/Http/Kernel.php:

‘web’ => [

    // …

    App\Http\Middleware\HandleInertiaRequests::class,

],

Client-Side Setup

  1. Install Vue.js and Inertia.js for the frontend using npm:

npm install @inertiajs/inertia @inertiajs/inertia-vue3

npm install vue@next

  1. Create the Inertia.js app setup in resources/js/app.js:

import “./bootstrap”;

import “../css/app.css”;

import { createApp, h } from “vue”;

import { createInertiaApp } from “@inertiajs/inertia-vue3”;

import { resolvePageComponent } from “laravel-vite-plugin/inertia-helpers”;

createInertiaApp({

  title: (title) => `${title} – ${appName}`,

  resolve: (name) =>

    resolvePageComponent(

      `./Pages/${name}.vue`,

      import.meta.glob(“./Pages/**/*.vue”)

    ),

  setup({ el, app, props, plugin }) {

    return createApp({ render: () => h(app, props) })

      .use(plugin)

      .mount(el);

  },

});

  1. Install the Vite Vue plugin:

npm i @vitejs/plugin-vue

  1. Update the vite.config.js file:

import { defineConfig } from “vite”;

import laravel from “laravel-vite-plugin”;

import vue from “@vitejs/plugin-vue”;

export default defineConfig({

  plugins: [

    laravel({

      input: [“resources/css/app.css”, “resources/js/app.js”],

      refresh: true,

    }),

    vue({

      template: {

        transformAssetUrls: {

          base: null,

          includeAbsolute: false,

        },

      },

    }),

  ],

});

  1. Finally, run the following commands to install dependencies and compile your assets:

npm install

npm run dev

Now, you’ve successfully integrated Laravel with Vue.js and Inertia.js! Your app is ready, and you can continue building your blog application with dynamic pages powered by Inertia.js.

Creating Inertia Pages

In this section, we’ll learn how to create Inertia pages in a Laravel application. The goal is to replace traditional Blade templates with Vue.js components and load them dynamically using Inertia. We will create components for the homepage, the article view, and a layout to organize the content efficiently.

Step 1: Set Up the Pages Folder

To organize your Vue.js components, start by creating a Pages folder inside the resources/js directory:

resources/js/Pages

Next, move the Blade components you created earlier (such as the homepage index.blade.php and article view show.blade.php) into this folder as .vue files.

For example:

  • Rename index.blade.php to Index.vue
  • Rename show.blade.php to Show.vue

Use uppercase letters for the component names to follow Vue.js conventions.

Step 2: Convert Blade Templates into Vue Components

Now, let’s transform the content of these Blade files into standard Vue.js components.

Creating Index.vue

For the homepage (index.blade.php), the new Vue component in resources/js/Pages/Index.vue will look like this:

<script setup>

// Add any necessary JavaScript or Vue-specific logic here

</script>

<template>

  <header>

    <h1>Devrims Blog</h1>

  </header>

  <main>

    <h2>Read our latest articles</h2>

    <section>

      <article>

        <div>

          <img src=”/images/devrims-logo.png” alt=”Article thumbnail” />

        </div>

        <h3>Title for the blog</h3>

        <p>Article content goes here.</p>

        <a href=”#”>Read more</a>

      </article>

    </section>

  </main>

  <footer>

    <h2>Join our Newsletter</h2>

    <input type=”email” />

  </footer>

</template>

This will serve as the homepage for the Devrims Blog. It will display a list of articles and a newsletter sign-up form.

Creating Show.vue

Next, create Show.vue for individual blog posts. In resources/js/Pages/Show.vue, the article content is displayed like this:

<script setup>

// Add any necessary script or logic here

</script>

<template>

  <header>

    <h1>Welcome to Devrims Blog</h1>

  </header>

  <main>

    <article>

      <h1>Title for the blog</h1>

      <p>Article content goes here.</p>

    </article>

  </main>

  <footer>

    <h2>Join our Newsletter</h2>

    <input type=”email” />

  </footer>

</template>

This page will display a single article, with the content passed dynamically via Inertia.js.

Step 3: Create a Layout Component

To keep things organized, it’s a good idea to create a layout component that wraps our pages, such as the header and footer.

Creating the Layout Component

Create a Layouts folder inside resources/js:

resources/js/Layouts

Inside the Layouts folder, create a file called CWLayout.vue:

<script setup>

// Add any necessary script or logic here

</script>

<template>

  <header>

    <h1>Devrims Blog</h1>

  </header>

  <main>

    <slot />

  </main>

  <footer>

    <h2>Join our Newsletter</h2>

    <input type=”email” />

  </footer>

</template>

In this layout, we define a simple header and footer, and the <slot /> allows the content of individual pages to be inserted dynamically into the layout.

Step 4: Use the Layout in Pages

Now that we have the layout, we can use it in Index.vue and Show.vue to wrap the page content.

Wrapping Index.vue with the Layout

In resources/js/Pages/Index.vue, import the CWLayout.vue layout and wrap the page content inside the layout:

<script setup>

import CWLayout from “../Layouts/CWLayout.vue”;

</script>

<template>

  <CWLayout>

    <section>

      <h2>Read our latest articles</h2>

      <article>

        <div>

          <img src=”/images/devrims-logo.png” alt=”Article thumbnail” />

        </div>

        <h3>Title for the blog</h3>

        <p>Article content goes here!</p>

        <a href=”#”>Read more</a>

      </article>

    </section>

  </CWLayout>

</template>

Using the CWLayout wrapper, the homepage content will be displayed within the predefined structure of the header, footer, and main content area.

Wrapping Show.vue with the Layout

Similarly, in Show.vue, import, and use the CWLayout.vue layout to wrap the article content:

<script setup>

import CWLayout from “../Layouts/CWLayout.vue”;

</script>

<template>

  <CWLayout>

    <article>

      <h1>Title for the blog</h1>

      <p>Article content goes here.</p>

    </article>

  </CWLayout>

</template>

This structure ensures that the article page will have the same header and footer as the homepage, maintaining consistency across the site.

Laravel Routes and Inertia Render

In this section, we’ll set up routes for our Devrims Blog application and learn how to use Inertia.js to pass data from the Laravel backend to the Vue.js frontend.

Step 1: Seed the Database with Demo Articles

Before setting up the routes, let’s seed the database with demo articles, which will be displayed on the blog’s homepage.

First, create a seeder for the Article model. In the database/seeders/DatabaseSeeder.php file, add the following code:

namespace Database\Seeders;

use App\Models\Article;

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder

{

    public function run()

    {

        Article::factory(10)->create();  // Create 10 demo articles

    }

}

Now, run the following command to migrate the tables and seed the fake data into the database:

php artisan migrate:fresh –seed

This will create 10 demo articles in the articles table, which we will use on the homepage.

Step 2: Defining Routes in web.php

Since we’re using Inertia.js to render views, we’ll set up the routes in the routes/web.php file. Instead of returning Blade views, we will use Inertia’s render method to load Vue.js components.

Add the following route in routes/web.php to handle the homepage:

use App\Models\Article;

use Illuminate\Support\Facades\Route;

use Inertia\Inertia;

Route::get(‘/’, function () {

    return Inertia::render(‘Index’, [

        ‘articles’ => Article::latest()->get()  // Pass articles to the view

    ]);

})->name(‘home’);

Here, we fetch the latest articles from the database and pass them as a prop to the Index component. The Inertia::render() method loads the Index.vue page and passes the article’s data to it.

Step 3: Accessing the Data in Vue.js (Inertia Page)

Next, let’s modify the Index.vue page to receive the articles as a prop and display them dynamically. In the resources/js/Pages/Index.vue file, we define the article’s prop and loop through it to display the articles.

Here’s how you can set up the Index.vue file:

<script setup>

import CWLayout from “../Layouts/CWLayout.vue”;

defineProps({

  articles: Array,  // Define the articles prop as an array

});

</script>

<template>

  <CWLayout>

    <h2>Read our latest articles</h2>

    <section>

      <!– Looping over articles –>

      <article v-for=”article in articles” :key=”article.id”>

        <div>

          <img src=”/images/devrims-logo.png” alt=”Article thumbnail” />

        </div>

        <h3>{{ article.title }}</h3>

        <p>{{ article.excerpt }}</p>

        <a href=”#”>Read more</a>

      </article>

    </section>

  </CWLayout>

</template>

In this template, we loop over the article’s prop using v-for to display each article’s title, excerpt, and a placeholder “Read more” link. The article’s prop is passed from the Laravel backend via the route.

Step 4: Handling Data in the Show Page

If you want to display individual articles on a separate page, you can define a route for the show page and pass the article data to it.

In routes/web.php, add a route to display an individual article:

Route::get(‘/articles/{article}’, function (Article $article) {

    return Inertia::render(‘Show’, [

        ‘article’ => $article  // Pass the article data to the show page

    ]);

})->name(‘article.show’);

Next, create the Show.vue component to render the article details. In resources/js/Pages/Show.vue, we access the article data and display it like this:

<script setup>

import CWLayout from “../Layouts/CWLayout.vue”;

defineProps({

  article: Object,  // Define the article prop as an object

});

</script>

<template>

  <CWLayout>

    <article>

      <h1>{{ article.title }}</h1>

      <p>{{ article.body }}</p>

    </article>

  </CWLayout>

</template>

In this component, we display the full content of the article, including its title and body. The article prop is passed from the route and contains the data of the selected article.

Using Tailwind CSS with Inertia.js

One of the best features of Inertia.js is how easily it integrates with frontend tools like Tailwind CSS. Since Tailwind is already installed in your project when setting up Laravel Inertia, all that’s left is to ensure your Inertia components are appropriately styled. Let’s walk through the steps to achieve this.

Step 1: Configure Tailwind to Work with Inertia Components

To ensure Tailwind CSS can style the components in your Inertia-based app, you need to update the tailwind.config.js file. This tells Tailwind where to look for HTML and Vue.js files in the project.

Here’s how you can update the tailwind.config.js:

/** @type {import(‘tailwindcss’).Config} */

module.exports = {

  content: [

    “./storage/framework/views/*.php”,

    “./resources/views/**/*.blade.php”,

    “./resources/js/**/*.vue”, // Make sure Inertia components are included here

  ],

  theme: {

    extend: {},

  },

  plugins: [],

};

This ensures that Tailwind scans all .vue files within resources/js and applies its styles accordingly.

Step 2: Import the Tailwind CSS File

Next, ensure the Tailwind CSS file is included in your app.js file. This allows Tailwind’s styles to be applied globally across your Vue.js components.

In resources/js/app.js, import the CSS file like this:

import “../css/app.css”;

Now, Tailwind CSS is ready to be used in your Inertia.js components.

Step 3: Styling the Index.vue Component

Let’s take the Index.vue component, where we display the articles and apply some Tailwind styles to make them look more appealing.

Here’s an example of how you might structure and style the Index.vue component:

<script setup>

import CWLayout from “../Layouts/CWLayout.vue”;

defineProps({

  articles: Array, // Expecting an array of articles

});

</script>

<template>

  <CWLayout>

    <h2 class=”text-2xl font-bold py-10″>Read our latest articles</h2>

    <section class=”space-y-5 border-b-2 pb-10″>

      <!– Looping through articles –>

      <article

        v-for=”article in articles”

        :key=”article.id”

        class=”flex justify-center items-center shadow-md bg-white rounded-xl p-4 mx-auto max-w-3xl”

      >

        <img

          src=”/images/CW-logo.png”

          class=”w-32 h-32 rounded-xl object-cover”

          alt=”Article thumbnail”

        />

        <div class=”flex flex-col text-left justify-between pl-3 space-y-5″>

          <h3

            class=”text-xl font-semibold text-indigo-600 hover:text-indigo-800″

          >

            <a href=”#”>{{ article.title }}</a>

          </h3>

          <p>{{ article.excerpt }}</p>

          <a

            href=”#”

            class=”text-indigo-600 hover:text-indigo-800 w-fit self-end font-semibold”

            >Read more</a

          >

        </div>

      </article>

    </section>

  </CWLayout>

</template>

In this component:

  • The h2 header is styled to be bold and has padding applied.
  • Each article is styled using a flexbox layout to center the content and apply padding, shadow, and rounded corners.
  • The article’s image is styled with Tailwind classes for size, rounded corners, and an object-fit property for better image scaling.
  • The article title and “Read more” links are styled with color classes, hover effects, and font settings.

Step 4: Styling the Layout Component

Now, let’s move on to the layout component, CWLayout.vue, where we can define styles for the header, footer, and main container. This layout component will be used across multiple pages to give the app a consistent look and feel.

Here’s an example of how to style the layout with Tailwind CSS:

<script setup></script>

<template>

  <header class=”bg-gradient-to-r from-blue-700 via-indigo-700 to-blue-700 w-full text-center py-4″>

    <h1 class=”text-white font-bold text-4xl”>Devrims Blog</h1>

  </header>

  <main class=”container mx-auto text-center”>

    <slot /> <!– This will be replaced by the content of the page –>

  </main>

  <footer class=”bg-gradient-to-b from-transparent to-gray-300 w-full text-center mt-5 py-10 mx-auto”>

    <h2 class=”font-bold text-xl pb-5″>Join our Newsletter</h2>

    <input

      class=”rounded-xl w-80 h-12 px-3 py-2 shadow-md”

      type=”email”

      placeholder=”Write your email..”

    />

  </footer>

</template>

In this layout:

  • The header uses a gradient background with large, bold, white text.
  • The main section has a container class for proper alignment and spacing.
  • The footer also uses a gradient, and the newsletter input field is styled with Tailwind classes for rounded corners and shadows.

Step 5: Final Touches

With Tailwind CSS integrated into your Inertia.js app, you can create a stylish and responsive blog layout. You can also continue customizing and extending the Tailwind utility classes to match your design preferences.

Inertia’s primary goal is to provide the experience of a single-page application (SPA) while using Laravel’s powerful backend. One of the key features that helps achieve this is the <Link> component. It works like a regular anchor tag (<a>) but with extra functionality that avoids full page reloads.

Now that our homepage displays articles let’s add functionality to allow you to view individual articles. We’ll create a route to view a specific article and set up links to navigate it without refreshing the page.

Step 1: Define Routes for Viewing Articles

First, we must define a route in routes/web.php to display an individual article. We’ll use Laravel’s route model binding to fetch the article automatically based on its ID.

Here’s how you can add the new route:

<?php

use App\Models\Article;

use Illuminate\Support\Facades\Route;

use Inertia\Inertia;

Route::get(‘/’, function () {

    return Inertia::render(‘Index’, [

        ‘articles’ => Article::latest()->get(),

    ]);

})->name(‘home’);

Route::get(‘/posts/{article:id}’, function (Article $article) {

    return Inertia::render(‘Show’, [

        ‘article’ => $article,

    ]);

})->name(‘article.show’);

In this code:

  • The Route::get(‘/posts/{article:id}’, …) route accepts an id parameter and uses Laravel’s route model binding to fetch the article directly from the database.
  • The Inertia::render(‘Show’, [‘article’ => $article]) method renders the Show.vue component and passes the article data to it.

Now that we have the route in place, we need a way to navigate to individual articles from the homepage. This is where Inertia’s <Link> component comes in. The <Link> component allows us to navigate to different pages without refreshing the entire page, ensuring a smooth and fast user experience.

In our Index.vue component, we’ll import the Link component from Inertia and replace the regular <a> tags with <Link> components. This ensures seamless navigation.

Here’s how to do that:

<script setup>

import DevrimsLayout from “../Layouts/DevrimsLayout.vue”;

import { Link } from “@inertiajs/inertia-vue3”;

defineProps({

    articles: Array,

});

</script>

<template>

  <DevrimsLayout>

    <section class=”space-y-5 border-b-2 pb-10″>

      <h2 class=”text-2xl font-bold pt-10 mx-auto text-center”>

        Read our latest articles

      </h2>

      <article

        v-for=”article in articles”

        :key=”article.id”

        class=”flex justify-center items-center shadow-md bg-white rounded-xl p-4 mx-auto max-w-3xl”

      >

        <img

          src=”/images/Devrims-logo.png”

          class=”w-32 h-32 rounded-xl object-cover”

          alt=”Article thumbnail”

        />

        <div class=”flex flex-col text-left justify-between pl-3 space-y-5″>

          <h3

            class=”text-xl font-semibold text-indigo-600 hover:text-indigo-800″

          >

            <Link :href=”‘/posts/’ + article.id”>{{ article.title }}</Link>

          </h3>

          <p>{{ article.excerpt }}</p>

          <Link

            :href=”‘/posts/’ + article.id”

            class=”text-indigo-600 hover:text-indigo-800 w-fit self-end font-semibold”

            >Read more</Link

          >

        </div>

      </article>

    </section>

  </DevrimsLayout>

</template>

In this code:

  • We imported the Link component from Inertia to replace the <a> tag.
  • The href attribute is dynamically set to the URL of the individual article, using the article.id as part of the path (i.e., /posts/{article.id}).
  • The Link component works like a regular anchor tag but without causing a page to reload.

Step 3: Displaying the Article in Show.vue

Next, we need to create the Show.vue component to display each article. This component will receive the article data as a prop and render it accordingly.

Here’s an example of how you can set up Show.vue:

<script setup>

import DevrimsLayout from “../Layouts/DevrimsLayout.vue”;

defineProps({

    article: Object,

});

</script>

<template>

  <DevrimsLayout>

    <article class=”mx-auto mt-10 flex justify-center max-w-5xl border-b-2″>

      <img

        src=”/images/Devrims-logo.png”

        class=”w-80 h-80 rounded-xl mx-auto py-5″

        alt=”Article Image”

      />

      <div class=”text-left flex flex-col pt-5 pb-10 px-10″>

        <h1 class=”text-xl font-semibold mb-10″>{{ article.title }}</h1>

        <p>{{ article.body }}</p>

      </div>

    </article>

  </DevrimsLayout>

</template>

In this component:

  • We use defineProps to expect an article object passed from the route in Index.vue.
  • The article title and body are displayed with some Tailwind CSS styling.

When you visit the homepage and click on the article title or the “Read more” link, Inertia will seamlessly load the Show.vue component for the individual article without refreshing the page. You will see the article’s details displayed in a styled layout.

While in the example above, we used <Link> to perform a simple GET request, Inertia’s <Link> component is quite versatile. It can also trigger other HTTP methods like POST, PUT, PATCH, or DELETE, turning it into a button or a form.

For example, if you want to log the user out without refreshing the page, you can do so with:

<Link href=”/logout” method=”post” as=”button” type=”button”>Logout</Link>

This example uses the method=”post” attribute to send a POST request when the link is clicked, and the as=”button” attribute turns the link into a button element.

Laravel Inertia Tips and Tricks You Should Know

Now that you have a working SPA using Laravel, Inertia, and Tailwind CSS, it’s time to explore some advanced Inertia techniques that will make your development process smoother and enhance your application’s performance and usability. Here are some helpful tips and tricks for working with Inertia:

1. Generating URLs with Named Routes

Inertia makes it easy to work with dynamic URLs without manually writing out complete URLs. If you’re using named routes in Laravel, you can use the route() helper function to generate URLs dynamically. This is especially useful when your routes have multiple parameters.

To integrate this into your Inertia app, use the Ziggy package. This package allows you to generate named routes within your Inertia components.

Install Ziggy:

composer require tightenco/ziggy

Then, in your resources/js/app.js file, import and configure Ziggy:

import { createApp, h } from “vue”;

import { createInertiaApp } from “@inertiajs/inertia-vue3”;

import { resolvePageComponent } from “laravel-vite-plugin/inertia-helpers”;

import { ZiggyVue } from “../../vendor/tightenco/ziggy/dist/vue.m”;

createInertiaApp({

    title: (title) => `${title} – ${appName}`,

    resolve: (name) => resolvePageComponent(`./Pages/${name}.vue`, import.meta.glob(“./Pages/**/*.vue”)),

    setup({ el, app, props, plugin }) {

        return createApp({ render: () => h(app, props) })

            .use(plugin)

            .use(ZiggyVue, Ziggy)

            .mount(el);

    },

});

Next, include the @routes directive in your resources/views/app.blade.php file to make sure Ziggy is available in your JavaScript:

<head>

    <meta charset=”utf-8″>

    <meta name=”viewport” content=”width=device-width, initial-scale=1″>

    <title inertia>{{ config(‘app.name’, ‘Laravel’) }}</title>

    @routes

    @vite(‘resources/js/app.js’)

    @inertiaHead

</head>

After setting this up, you can replace manually typed URLs with your components’ route() helper. For example, change:

<Link :href=”‘/posts/’ + article.id”>{{ article.title }}</Link>

To:

<Link :href=”route(‘article.show’, article.id)”>{{ article.title }}</Link>

This approach makes your code cleaner, less error-prone, and more flexible if route definitions change in the future.

2. Progress Indicators

SPAS needs to provide feedback to users during navigation. Inertia includes a built-in progress indicator using the @inertiajs/progress library. When data is being loaded, a loading bar and spinner appear.

To set it up, first install the package:

npm install @inertiajs/progress

Then, import and configure it in your resources/js/app.js file:

import { InertiaProgress } from “@inertiajs/progress”;

InertiaProgress.init({

    color: “#000000”, // Customize the color of the loading bar

    showSpinner: true, // Show the loading spinner

});

This adds a smooth loading bar at the top of the screen when navigating between pages. The Inertia.js documentation provides customization options for the progress indicator’s appearance and behavior.

3. Scroll Management

Sometimes, users want to keep their scroll position when navigating between pages. For example, after submitting a comment, you may want to reload the page to show the new comment but retain the user’s scroll position.

Inertia offers a preserve-scroll attribute for its <Link> component to achieve this. It ensures that the scroll position is preserved when navigating to a new page.

Here’s how to use it:

<Link :href=”route(‘article.show’, article.id)” preserve-scroll>

    {{ article.title }}

</Link>

This keeps the user’s scroll position intact when they click on a link and navigate to another page, which is excellent for a smooth user experience in SPAs.

4. Handling Form Submissions

Inertia also allows you to handle form submissions seamlessly without reloading the page. You can use the <Link> component to send POST, PUT, PATCH, or DELETE requests as if they were buttons or forms. This is useful for logging out, submitting a form, or deleting a resource.

For example, to trigger a logout via a button without refreshing the page:

<Link href=”/logout” method=”post” as=”button” type=”button”>Logout</Link>

This sends a POST request to the /logout route when the button clicks, just like a traditional form submission, but without causing a page to reload.

5. Nested Layouts

Inertia supports nested layouts, allowing you to create reusable layout components that can be extended throughout your application. This helps keep your code DRY (Don’t Repeat Yourself).

For example, you can have a global layout with a header, sidebar, and footer and then inject specific page content into the main content area.

Here’s how to use nested layouts:

In resources/js/Layouts/DefaultLayout.vue:

<template>

  <header>

    <!– Header content –>

  </header>

  <main>

    <slot></slot>

  </main>

  <footer>

    <!– Footer content –>

  </footer>

</template>

In resources/js/Pages/Article/Show.vue:

<template>

  <DefaultLayout>

    <h1>{{ article.title }}</h1>

    <p>{{ article.body }}</p>

  </DefaultLayout>

</template>

This method allows you to reuse common layout structures while keeping flexibility for specific page content.

6. Handling Flash Messages

Inertia makes passing and displaying flash messages, such as success or error notifications, easy. You can pass messages from the controller to the Inertia response and display them in your components.

For example, in your Laravel controller:

return Inertia::render(‘Dashboard’, [

    ‘message’ => session(‘message’)

]);

Then, in your Vue component:

<template>

  <div v-if=”message” class=”alert alert-success”>

    {{ message }}

  </div>

</template>

<script setup>

defineProps({

  message: String,

});

</script>

This allows you to display messages on the frontend without reloading the page, maintaining the smooth experience that Inertia provides.

SEO Tips for Laravel Inertia

Since the rise of single-page applications (SPAs), search engine optimization (SEO) has become more challenging. Traditional SPAs render content on the client side using JavaScript, which search engines often struggle to crawl. This can hurt your website’s visibility in search results. However, platforms like Facebook and GitHub successfully use SPAs and maintain strong SEO, proving that achieving good SEO performance with a SPA is possible.

Inertia.js offers several solutions to help make your SPA more SEO-friendly and ensure search engines easily index your Laravel-based Inertia app.

1. Server-Side Rendering (SSR) with Vue and Laravel

One of the best ways to improve SEO for your Laravel Inertia SPA is by enabling Server-Side Rendering (SSR). SSR allows the server to render the initial page request and send fully-rendered HTML to the browser, which makes it easier for search engines to crawl your site. It also provides a faster, more interactive experience for users.

Here’s how SSR works with Inertia.js and Vue:

  • Initial Page Rendering: When a user or search engine bot requests a page, the server renders it and sends the HTML back instead of relying on JavaScript to render the page in the browser.
  • Search Engine Friendly: This pre-rendering allows search engines to quickly parse the page content without executing JavaScript.

To implement SSR in your Laravel Inertia app, you must set up a Node.js service to render Vue components. Laravel is a PHP framework that does not run on a Node.js server. The server will render the components and return the HTML to the client.

Steps to Set Up SSR:

  1. Install the required packages:

npm install @vue/server-renderer @inertiajs/server

  1. Create an SSR entry file in resources/js/ssr.js: This file is similar to your regular app.js but designed to run on a Node.js server:

import { createSSRApp, h } from “vue”;

import { renderToString } from “@vue/server-renderer”;

import { createInertiaApp } from “@inertiajs/inertia-vue3”;

import createServer from “@inertiajs/server”;

import { resolvePageComponent } from “laravel-vite-plugin/inertia-helpers”;

import { ZiggyVue } from “../../vendor/tightenco/ziggy/dist/vue.m”;

const appName = “Laravel”;

createServer((page) =>

    createInertiaApp({

        page,

        render: renderToString,

        title: (title) => `${title} – ${appName}`,

        resolve: (name) =>

            resolvePageComponent(

                `./Pages/${name}.vue`,

                import.meta.glob(“./Pages/**/*.vue”)

            ),

        setup({ app, props, plugin }) {

            return createSSRApp({ render: () => h(app, props) })

                .use(plugin)

                .use(ZiggyVue, {

                    …page.props.ziggy,

                    location: new URL(page.props.ziggy.location),

                });

        },

    })

);

  1. Configure Vite for SSR: In vite.config.js, specify the SSR entry file:

import { defineConfig } from “vite”;

import laravel from “laravel-vite-plugin”;

import vue from “@vitejs/plugin-vue”;

export default defineConfig({

    plugins: [

        laravel({

            input: “resources/js/app.js”,

            ssr: “resources/js/ssr.js”,

        }),

        vue({

            template: {

                transformAssetUrls: {

                    base: null,

                    includeAbsolute: false,

                },

            },

        }),

    ],

});

  1. Update your build script in package.json:

“build”: “vite build && vite build –ssr”

After completing this setup, run npm run build to generate your SSR bundle and prepare your app for production.

2. Title and Meta Tags for SEO

SEO depends heavily on proper metadata for each page, including the <title> and <meta> tags. Since JavaScript applications only render content inside the <body>, they don’t naturally modify the <head> section of the document. Fortunately, Inertia provides a <Head> component to set page titles and meta tags dynamically.

How to Use Inertia’s <Head> Component:

  1. Import the <Head> Component from Inertia in your Vue component:

import { Head } from ‘@inertiajs/inertia-vue3’;

  1. Set the <title> and other meta tags in your page component:

<template>

  <Head>

    <title>My Awesome Blog</title>

    <meta name=”description” content=”A blog about Laravel and Inertia.js.” />

    <meta name=”keywords” content=”Laravel, Inertia, Vue.js, SEO” />

  </Head>

</template>

You can also set a global title for all pages. For example, in your app.js file:

createInertiaApp({

    title: (title) => `${title} – My Laravel App`,

    …

});

This ensures that each page has meaningful titles and metadata, which is crucial for SEO and social sharing.

3. Monitor Your Application’s Performance

Website speed is an essential factor in SEO rankings. Slow loading times can negatively impact user experience and search engine rankings. Consider using performance monitoring tools to optimize your Laravel Inertia app’s performance.

You can use tools like Google Lighthouse or WebPageTest to track performance issues. These tools provide insights into essential SEO factors such as Time to First Byte (TTFB), page load times, and Core Web Vitals.

4. Server-side rendering and Dynamic Content

If your content is dynamic, such as blog posts or news feeds, search engines must be able to crawl it. With SSR, content is rendered on the server and delivered as HTML. However, if the content changes frequently, ensure that search engines always receive up-to-date HTML.

For instance, if you’re fetching blog posts dynamically, ensure the initial HTML served to search engines contains the most recent content. Using Inertia’s SSR with Vue’s server-side rendering capabilities will ensure search engines can index your dynamic content immediately.

By implementing these strategies, you can improve your Laravel Inertia app’s SEO and ensure that search engines index your content efficiently.

Conclusion

Inertia.js has become one of the most powerful tools for building modern Single-Page Applications (SPAs), and when paired with Laravel, it unlocks even greater possibilities. This smooth integration of PHP and JavaScript allows developers to build highly interactive apps without losing the power and simplicity of Laravel’s backend.

With official support for Inertia.js in popular Laravel starter kits like Breeze and Jetstream, it’s clear that Inertia is here to stay. It enables developers to create fast, dynamic, and SEO-friendly SPAs that feel like native apps, all while maintaining the structure of traditional server-rendered applications.

In this blog, we’ve covered how to get started with Laravel Inertia, created basic pages, and explored advanced topics like routing, SEO optimization, and helpful Inertia tips. While this tutorial is a great starting point, there’s much more to discover about Inertia. As you continue developing and improving your applications, you’ll uncover even more powerful features Inertia has to offer.

Whether you’re a Laravel enthusiast or a professional developer looking to improve your workflow, Inertia.js is worth exploring. We hope this article has inspired you to build modern SPAs with Laravel and Inertia, and we encourage you to explore this innovative technology further.

What else would you like us to explore about Laravel or Inertia? Share your thoughts and suggestions in the comments below. We’d love to hear from you!

The Author

Anmol is a dedicated technical content writer known for her practical approach. She believes in experiencing processes firsthand before translating them into insightful content. Additionally, she is good at WordPress development and skills of digital forensics and cybersecurity. Beyond her professional endeavors, she enjoys playing sports games, particularly table tennis and badminton, valuing the balance between mental and physical agility.

Scroll to Top