Skip to content

Customizing Built-in Sections

FilamentCraft's built-ins are defaults, not sealed components. You can adjust one section instance in the editor, reskin every section through the theme, create a no-code section, or take application-level ownership of a built-in with one command.

This guide covers that last case: creating a code-owned variant or replacing a built-in while keeping existing template data intact.

Choose the smallest customization that works

GoalBest tool
Change the copy, media, layout, scheme, or blocks on one pageEdit that section instance in the visual editor
Change colors, typography, spacing, buttons, or schemes across the siteTheme and design tokens
Let an editor assemble a reusable section without PHPNo-Code Section Builder
Add a new behavior or schema derived from a built-inCreate a variant with this command
Change how every existing instance of a built-in rendersCreate a replacement with --replace

If a theme or ordinary section setting solves the problem, prefer it. A code-level customization is most useful when you need new schema fields, different markup, application services, or behavior specific to the host app.

Guided workflow

Run the command without arguments:

bash
php artisan filamentcraft:customize-section

The command walks through five decisions:

  1. Search all 32 built-ins by name or slug.
  2. Create a new variant or replace the selected built-in everywhere.
  3. Confirm the generated class name and, for a variant, its new slug.
  4. Inherit the package view or copy it into the application.
  5. Review the impact summary before any files are written.

Variant mode is recommended and selected by default. Replacement mode requires an explicit confirmation because it changes how existing page and region instances resolve.

Create a safe variant

Use a variant when the original built-in should remain available:

bash
php artisan filamentcraft:customize-section hero ProductHero

This creates app/Sections/ProductHeroSection.php, auto-discovered by FilamentCraft under the new product-hero slug. The generated class inherits the Hero's settings, blocks, presets, defaults, preview image, caching rules, and Blade view.

The generated class is deliberately small:

php
<?php

declare(strict_types=1);

namespace App\Sections;

use FilamentCraft\Sections\Builtin\HeroSection as BuiltinHeroSection;

final class ProductHeroSection extends BuiltinHeroSection
{
    public static function slug(): string
    {
        return 'product-hero';
    }

    public static function name(): string
    {
        return 'Product Hero';
    }
}

Open Add section after generation. Both Hero and Product Hero are available; pages already using hero are unchanged.

Choose a different slug for automated runs with --slug:

bash
php artisan filamentcraft:customize-section hero ProductHero \
    --slug=commerce-hero \
    --no-interaction

The command refuses a variant slug already owned by a built-in or registered custom section.

Own the Blade markup

Add --copy-view only when the markup itself needs to change:

bash
php artisan filamentcraft:customize-section hero ProductHero --copy-view

In addition to the class, this writes:

text
resources/views/sections/product-hero.blade.php

The generated class points to sections.product-hero. Edit that view normally; the existing $section, $section->settings, blocks, live-update attributes, theme components, and design tokens continue to work.

There is an upgrade tradeoff:

  • Inherit the view — package fixes and markup improvements arrive automatically.
  • Copy the view — the application owns the markup completely, but future package changes cannot merge into it automatically.

Keep copied views in version control and compare them with the corresponding package view when upgrading FilamentCraft.

Replace a built-in everywhere

Use --replace when every existing instance should resolve through the host subclass:

bash
php artisan filamentcraft:customize-section hero ApplicationHero --replace

Replacement mode preserves the source slug (hero). FilamentCraft registers built-ins first and application sections afterward, so the host subclass intentionally wins. Stored templates and regions do not need to be migrated or rewritten.

To own the markup too:

bash
php artisan filamentcraft:customize-section hero ApplicationHero \
    --replace \
    --copy-view

Replacement mode preserves data, but schema compatibility remains your responsibility:

  • Keep existing setting and block keys when old pages still contain them.
  • Add new settings with defaults so older revisions render predictably.
  • If you remove a field, make the copied view tolerant of its legacy stored value.
  • Test page sections and site-wide regions; the same slug can appear in either.

--slug is rejected with --replace. A replacement must retain the built-in slug or it would be a variant rather than a replacement.

Extend settings without rebuilding the schema

Override only the method you need and compose with the parent:

php
use FilamentCraft\Settings\Types\Text;

public static function settings(): array
{
    return [
        ...parent::settings(),
        Text::make('campaign_label')->label('Campaign label'),
    ];
}

Merge a default into the inherited payload instead of replacing it:

php
public static function defaults(): array
{
    $defaults = parent::defaults();
    $defaults['settings']['campaign_label'] = 'Featured';

    return $defaults;
}

The same approach works for blocks(), presets(), lookKnobs(), enabledOn(), and other section contract methods. Leaving a method untouched keeps following upstream improvements.

Contact and Newsletter remain Livewire components

The built-in contact and newsletter sections extend LivewireSection. A generated subclass inherits their public state, validation, actions, events, and Livewire registration behavior:

bash
php artisan filamentcraft:customize-section contact ConciergeContact

If you copy one of their views, preserve its wire:submit, field bindings, validation output, and success-state markup unless you are deliberately replacing that interaction.

Custom output paths

The conventional app/Sections directory needs no registration. For another directory, set the matching namespace and path:

bash
php artisan filamentcraft:customize-section pricing AgencyPlans \
    --namespace='App\Website\Sections' \
    --path=app/Website/Sections \
    --view-path=resources/views/website/sections \
    --copy-view

The command prints the exact ->registerSection(...) registration when the target is outside app/Sections.

Non-interactive and CI usage

Supply the source and class name explicitly:

bash
# Additive variant
php artisan filamentcraft:customize-section hero ProductHero --no-interaction

# Application-wide replacement
php artisan filamentcraft:customize-section hero ApplicationHero \
    --replace \
    --copy-view \
    --no-interaction

Existing targets fail safely. Use --force only when intentionally regenerating those exact files; the command validates every requested artifact before writing and restores overwritten targets if generation cannot complete.

Command reference

text
filamentcraft:customize-section
    {section?}
    {name?}
    {--replace}
    {--slug=}
    {--copy-view}
    {--namespace=App\Sections}
    {--path=app/Sections}
    {--view-path=resources/views/sections}
    {--force}
InputMeaning
sectionBuilt-in source slug, such as hero, pricing, or contact
nameGenerated class name; Section is appended when omitted
--replacePreserve the source slug and replace every matching instance
--slugCustom slug for a variant; invalid with --replace
--copy-viewCopy only the selected built-in Blade view into the application
--namespaceGenerated PHP namespace
--pathGenerated class directory relative to the application root
--view-pathCopied-view directory under resources/views
--forceReplace existing generated targets deliberately

Diagnose or roll back

Run the package doctor after creating a replacement:

bash
php artisan filamentcraft:doctor

An intentional subclass replacement appears as an OK check. An unrelated class taking the same slug remains a warning, which catches accidental collisions.

To roll back a conventional customization, delete its generated class (and copied view, if present), refresh autoloading, and run the doctor again:

bash
composer dump-autoload
php artisan filamentcraft:doctor

The package built-in resumes ownership of its slug. Stored template data was never rewritten, so no content rollback is required.