DEV Community

Cover image for Create a custom error page with Laravel and Inertia
Capsules Codes
Capsules Codes

Posted on • Originally published at capsules.codes

Create a custom error page with Laravel and Inertia

TL;DR: How to display a custom error page with Inertia instead of Laravel’s default error pages.

 
 

A sample Laravel project can be found on this Github Repository. Find out more on Capsules or X.

 
 

In a previous article, the focus was on customizing the 502 Bad Gateway error page servec by Nginx. This page was an HTML file placed directly in the /public folder. This article now focuses on customizing the error pages returned by Laravel in a VILT project.

 
 

To get a preview of the layout of Laravel’s default error pages, simply generate an error using the App::abort facade or the abort helper, followed by the desired error code.

 
 

routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\App;


Route::get( '/', fn() => App::abort( 503 ) );
Enter fullscreen mode Exit fullscreen mode

Capsules Error Image 1

 
 

Route::get( '/', fn() => App::abort( 419 ) );
Enter fullscreen mode Exit fullscreen mode

Capsules Error Image 2

 
 

Route::get( '/', fn() => App::abort( 404 ) );
Enter fullscreen mode Exit fullscreen mode

Capsules Error Image 3

 
 

By delving into the functionality of the abort function, it becomes clear that Laravel generates an Exception, which is then handled by the ExceptionHandler created by the withException method in the bootstrap/app.php file.

 
 

vendor/laravel/framework/src/Illuminate/Foundation/Application.php

public function abort($code, $message = '', array $headers = [])
{
    if ($code == 404) {
        throw new NotFoundHttpException($message, null, 0, $headers);
    }

    throw new HttpException($code, $message, null, $headers);
}
Enter fullscreen mode Exit fullscreen mode

 
 

vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php

protected function prepareResponse($request, Throwable $e)
{
    if (! $this->isHttpException($e) && config('app.debug')) {
        return $this->toIlluminateResponse($this->convertExceptionToResponse($e), $e)->prepare($request);
    }

    if (! $this->isHttpException($e)) {
        $e = new HttpException(500, $e->getMessage(), $e);
    }

    return $this->toIlluminateResponse(
        $this->renderHttpException($e), $e
    )->prepare($request);
}
Enter fullscreen mode Exit fullscreen mode

 
 

bootstrap/app.php

<?php

use Illuminate\Foundation\Application;

return Application::configure( basePath : dirname( __DIR__ ) )
    ->withRouting( web : base_path( "/routes/web.php" ) )
    ->withExceptions()
    ->create();
Enter fullscreen mode Exit fullscreen mode
  • If the withExceptions method is removed from the file, everything falls apart. Therefore, it is crucial not to overlook this method.

 
 

To allow Inertia to intercept the various exceptions, it is necessary to modify the bootstrap/app.php file. This is primarily where the magic happens.

 
 

More specifically, regarding the withExceptions method : it handles exception interception. When the exception is an HttpException, which is the focus of this article, the Inertia rendering is triggered. The method $exceptions->render( fn( HttpException $exception, ... ) ) allows filtering of exception types. If the exception is an HttpException, the Inertia rendering process continues. Inertia then returns the Error page with the $request response and its status code.

 
 

bootstrap/app.php

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Illuminate\Http\Request;
use Inertia\Inertia;


return Application::configure( basePath : dirname( __DIR__ ) )
    ->withRouting( web : base_path( "/routes/web.php" ) )
    ->withMiddleware()
    ->withExceptions( fn( Exceptions $exceptions ) =>

        $exceptions->render( fn( HttpException $exception, Request $request ) =>

            Inertia::render( 'Error', [ 'status' => $exception->getStatusCode() ] )
                   ->toResponse( $request )
                   ->setStatusCode( $exception->getStatusCode() )

        )
    )
    ->create();
Enter fullscreen mode Exit fullscreen mode

 
 

It is then possible to customize the desired error pages by using a dedicated Vue component Error for errors.

 
 

resources/js/pages/Error.vue

<script setup>

import { Head } from '@inertiajs/vue3'
import { useStatusName, useStatusMessage } from '~/composables/status';
import logotype from '/public/assets/capsules-logotype.svg';


const props = defineProps( { status : Number } );

</script>

<template>

    <Head>

        <title>{{ useStatusName( status ) }}</title>

    </Head>

    <div class="h-screen flex justify-center">

        <div class="flex items-center space-x-10">

            <img class="h-20 w-20" v-bind:src="logotype">

            <div class="flex flex-col items-start space-y-2 font-mono text-primary-black">

                <h1 class="text-2xl text-primary-blue" v-text="`${props.status} - ${useStatusName( status )}`" />

                <p class="text-md" v-text="useStatusMessage( status )" />

            </div>

        </div>

    </div>

</template>
Enter fullscreen mode Exit fullscreen mode
  • The Head component allows for customizing the <head> section of the HTML page. However, it is important not to forget to include @inertiaHead in the app.blade.php.

 
 

As well as a status composable that returns the desired error codes and messages.

 
 

resources/js/composables/status.js

export function useStatusName( status )
{
    switch( status )
    {
        case 503 : return 'Service Unavailable';
        case 500 : return 'Server Error';
        case 419 : return 'Session Expired';
        case 418 : return 'I\'m a teapot';
        case 404 : return 'Page Not Found';
        case 403 : return 'Forbidden';
        default : return 'Error';
    }
}

export function useStatusMessage( status )
{
    switch( status )
    {
        case 503 : return 'Sorry, we are doing some maintenance. Please check back soon.';
        case 500 : return 'Whoops, something went wrong on our servers.';
        case 419 : return 'Sorry, your session expired.';
        case 418 : return 'Sorry, I am not a coffee machine.';
        case 404 : return 'Sorry, the page you are looking for could not be found.';
        case 403 : return 'Sorry, you are forbidden from accessing this page.';
        default : return 'Sorry, something went wrong unexpectedly.';
    }
}
Enter fullscreen mode Exit fullscreen mode

 
 

To test different exceptions directly from the browser :

 
 

routes/web.php

<?php

use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\App;

Route::get( '/{status?}', fn( int | null $status = null ) => App::abort( $status ?? 418 ) );
Enter fullscreen mode Exit fullscreen mode
herd link article

npm run dev
Enter fullscreen mode Exit fullscreen mode

 
 

> http://article.test/503

Capsules Error Image 4

 
 

> http://article.test/419

Capsules Error Image 5

 
 

> http://article.test/404

Capsules Error Image 6

 
 

Glad this helped.

Top comments (0)