Skip to content

Child Themes ​

Introduction ​

A child theme takes everything it does not have from a base theme: page components, styles, images, migrations and the base theme's service provider. It is the natural way to build language or regional copies of a site, or a seasonal variant, without forking the theme.

The rule that keeps this maintainable: the base theme never knows its children. A child declares its base; the base's code needs no change when a child appears.

Declaring a child theme ​

The smallest child theme is just a composer.json that maps the new theme to its base:

json
{
    "name": "acme/my-theme-fr",
    "description": "French copy of the Acme theme.",
    "require": {
        "acme/my-theme": "^1.0"
    },
    "extra": {
        "laravel": {
            "themes": {
                "MyThemeFr": "MyTheme"
            }
        },
        "kitloom": {
            "theme": { "name": "Acme — Français" }
        }
    }
}

Without a package — a directory in themes/ — declare it in the config instead:

php
// config/kitloom-themes.php
return [
    'all' => ['MyThemeFr'],
    'base' => ['MyThemeFr' => 'MyTheme'],
];

kitloom-themes.base also overrides the base declared by a package. A theme without a package and without a base entry inherits from the default theme (APP_THEME).

What is inherited ​

WhatHow
Service providerThe base theme's provider runs when the base or any of its children is active — ThemeManager::isActiveOrBase(). The child needs no provider unless it adds behaviour.
Page components (Vue)The @ alias resolves a file from the child first, then from the base. Import base files explicitly with @base.
Stylesvirtual:theme-css is the child's resources/css/app.css, or the base's if the child has none.
Views (Blade)The child's resources/views come first.
MigrationsBase theme's first, then the child's.
Images and fontsCopied per theme into public/images/{Theme} and public/fonts/{Theme} — a child brings its own, or references the base's.

Overriding one component ​

To change only the post page in the French copy, put a single file in the child:

text
my-theme-fr/
├── composer.json
└── resources/js/Pages/Pages/Post/Index.vue

Every other component still comes from MyTheme. Inside the override you can reuse base components (assuming the base page exposes a footer slot):

vue
<script setup>
import BasePost from '@base/Pages/Pages/Post/Index.vue';
</script>

<template>
    <BasePost v-bind="$attrs">
        <template #footer>Lire aussi…</template>
    </BasePost>
</template>

A provider of its own ​

The base theme's provider already runs for every child, so a child usually needs no provider. If a child must add bindings of its own, keep them small and guard them with the child's name — app(ThemeManager::class)->isActive('MyThemeFr') — rather than extending the base provider: an extending provider would run the base theme's registration a second time.

Planned

A dedicated base class for child-theme providers — inheriting the base theme's behaviour and adding the child's own components — is planned.