Skip to content

Installing Themes ​

Introduction ​

Installing a theme takes three steps: require the package, build it if it is a Vue theme, and activate it. A site created from a skeleton has done all three at installation for the themes it kept, when it was let build them — otherwise run npm run build:themes, and activate the theme as in step 3; these are the steps for a theme added later. The site itself needs kitloom/site with its fallback route — see Installation.

1. Require the theme ​

A theme requires kitloom/site and, for a Vue theme, kitloom/site-inertia, so Composer installs them with it:

bash
composer require kitloom/portfolio-theme
# also installs kitloom/site-inertia and inertiajs/inertia-laravel
bash
composer require kitloom/blade-theme

The theme's service provider is discovered by Laravel; nothing is added to your application. For the Themes screen, add the package for your panel:

bash
composer require kitloom/site-filament
bash
composer require kitloom/site-nova

A theme in a folder of your application ​

Every folder under themes/ is a theme of that name — themes/Studio is the theme Studio. A folder with resources/js/Templates is a Vue theme, any other a Blade theme. No package and no provider are needed; another folder is set in kitloom-site.theme.path. See Writing a Theme.

2. Build it (Vue themes) ​

A Blade theme has nothing to build — go on to step 3.

A Vue theme is built with Vite, each theme into its own directory, public/build-{Theme}. kitloom/site-inertia brings the Vite plugin that finds the theme in themes/ or vendor/. The skeletons' vite.config.js:

js
import { defineConfig, loadEnv } from 'vite';
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import react from '@vitejs/plugin-react';
import kitloomTheme, { buildsWithVite, themeEntry } from './vendor/kitloom/site-inertia/vite/index.js';

export default defineConfig(({ mode }) => {
    // APP_THEME as the site reads it, from .env; the shell's wins.
    const theme = loadEnv(mode, process.cwd(), '').APP_THEME ?? '';

    // No theme, or a Blade one: nothing to build or serve.
    if (!buildsWithVite(theme)) {
        console.info('Vite has nothing to build.');
        process.exit(0);
    }

    return {
        plugins: [
            laravel({
                input: [themeEntry(theme)],
                buildDirectory: `build-${theme}`,
                refresh: true,
            }),
            ...kitloomTheme({ theme }),
            vue({
                template: {
                    transformAssetUrls: {
                        base: null,
                        includeAbsolute: false,
                    },
                },
            }),
            // A React theme's components; a Vue theme has none.
            react({ include: /\.[jt]sx$/ }),
        ],
        resolve: {
            preserveSymlinks: true,
        },
        server: {
            watch: {
                ignored: ['**/storage/framework/views/**'],
            },
        },
    };
});

kitloomTheme() returns three plugins, so it is spread into the list. preserveSymlinks matters when theme packages are symlinked into vendor/ from a Composer path repository; see Building Assets.

The theme's JavaScript is resolved from your application's node_modules. The bundled themes need these (the config above loads both the Vue and the React plugin):

bash
npm install -D vite@^7 laravel-vite-plugin@^2 @vitejs/plugin-vue@^6 @vitejs/plugin-react@^5
npm install vue@^3.5 @inertiajs/vue3@^3 axios

Some need more:

ThemeAlso needs
Saffron@glidejs/glide@^3.6
Atelierdate-fns@^4
Keystone, Waypointmaplibre-gl@6
Quire (React)react@^19 react-dom@^19 @inertiajs/react@^3

@inertiajs/vue3 and @inertiajs/react must be 3: the server side is inertiajs/inertia-laravel 3. A theme of your own may need more; the skeletons' package.json has all of the above.

Add a script that builds every theme:

json
{
    "scripts": {
        "dev": "vite",
        "build": "vite build",
        "build:themes": "node vendor/kitloom/site-inertia/vite/build-themes.js"
    }
}
bash
npm run build:themes                     # every installed Vue theme, one after another
APP_THEME=GameReviews npm run build      # one theme

build:themes builds every Vue theme it finds and takes no arguments. Each build writes its own manifest and the list of the theme's templates, so an administrator can switch between built themes without a rebuild.

Deploying

Run npm run build:themes in your deploy pipeline, so every installed theme is ready to be activated. A Vue theme that is not built cannot be activated: its card says Not built yet.

3. Activate the theme ​

Open Appearance → Themes and click Activate on the theme's card. Activation runs the theme's migrations, then switches the site to it — see The Themes screen.

From the console — a deploy script, a site without an admin yet — site:theme does the same:

bash
php artisan site:theme Journal   # its migrations, then the switch
php artisan site:theme --none    # no theme: every page answers as JSON
php artisan site:theme           # the installed themes, which is active, which is not built

Without an admin screen, or on a fresh install where nothing is selected yet, name the default theme in .env:

ini
APP_THEME=Portfolio

APP_THEME is used while the kitloom_theme option is not set (not WordPress's current_theme, which WordPress itself overwrites on a shared database), or names a theme that is not installed.

Theme migrations

A theme's migrations run when it is activated on the Themes screen. After that, the active theme's migrations go with php artisan migrate: a deploy that brings a new one runs it with the site's own, and a new environment whose kitloom_theme option or APP_THEME names the theme gets its tables from migrate. The migrations of themes that are not active wait for their activation.

Removing a theme ​

bash
composer remove kitloom/blade-theme

If the removed theme was active, the site falls back to APP_THEME, and to no theme at all when that is not installed either. Delete its build directory, public/build-{Theme}, too. Data the theme's migrations created stays in the database.

Running without a theme ​

The active theme's card has a Deactivate button. After a confirmation the site has no theme at all — APP_THEME is not used either — and every page answers with its data as JSON, for a headless front end. Activate on any card brings the rendered site back. See Headless & APIs.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]