Skip to content

Custom Sections ​

Custom sections are first-class citizens. Drop a class anywhere on the autoloader, extend BladeSection, and FilamentCraft renders it in the editor and on published pages — the same pipeline the built-in sections use.

A minimal section ​

php
namespace App\Sections;

use FilamentCraft\Sections\BladeSection;
use FilamentCraft\Settings\Types\Image;
use FilamentCraft\Settings\Types\Text;
use FilamentCraft\Settings\Types\Textarea;

final class TestimonialSection extends BladeSection
{
    protected static string $view = 'sections.testimonial';

    public static function slug(): string
    {
        return 'testimonial';
    }

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

    public static function settings(): array
    {
        return [
            Textarea::make('quote')->label('Quote')->required(),
            Text::make('author')->label('Author')->required(),
            Image::make('avatar')->label('Avatar'),
        ];
    }

    public static function defaults(): array
    {
        return [
            'settings' => [
                'quote' => 'A useful quote about the product.',
                'author' => 'Customer Name',
            ],
            'blocks' => [],
        ];
    }
}

The matching Blade view (resources/views/sections/testimonial.blade.php) receives a $section data object:

blade
<figure class="px-6 py-12 text-center">
    <blockquote class="text-2xl">{{ $section->settings->get('quote') }}</blockquote>
    <figcaption class="mt-4 text-sm text-gray-500">{{ $section->settings->get('author') }}</figcaption>
</figure>
A custom section's settings panel
A custom section's settings panel, generated from its static schema.

Scaffold it

php artisan make:filamentcraft-section Testimonial generates the class and Blade view (or a Livewire class with --livewire). See Make Commands.

The Section contract ​

BladeSection implements FilamentCraft\Sections\Contracts\Section via the SectionSchema trait, which supplies sensible defaults for everything except the view. Override only what you need:

MethodReturnsDefaultPurpose
slug()stringkebab of class name minus -sectionStable id stored in revisions.
name()stringheadline of the slugDisplay label in the catalog.
category()string'general'Catalog grouping.
description()?stringnullSub-label in the catalog.
icon()stringheroicon-o-puzzle-pieceCatalog icon.
maxBlocks()int16Cap on total blocks across all block types.
wrapper()string'section'The HTML tag/selector wrapping the rendered output.
settings()array[]The settings schema (see below).
blocks()array[]Repeatable child blocks.
presets()array[]Named starting points.
enabledOn()array['*']Template types the section is offered on.
disabledOn()array[]Template types to exclude.
previewImageUrl()?stringnullCatalog thumbnail.
defaults()array['settings' => [], 'blocks' => []]Initial content when added.

slug(), name(), settings(), and defaults() are the ones you'll usually define.

Settings ​

settings() returns an array of setting types. It can mix the FilamentCraft DSL with raw Filament v4 components — the compiler wires live() on every leaf field so the preview keeps updating, and resolves visibility from either the DSL's visibleIf([...]) shortcut or Filament's native visible(Closure) callback.

php
use Filament\Forms\Components\Toggle;
use Filament\Schemas\Components\Utilities\Get;
use FilamentCraft\Settings\Types\Group;
use FilamentCraft\Settings\Types\Text;

public static function settings(): array
{
    return [
        Group::make('content')->label('Content'),
        Text::make('heading')->label('Heading')->default('Welcome'),

        Group::make('cta')->label('Call to action')->collapsed(),
        Toggle::make('cta_enabled')->label('Show button')->default(true),
        Text::make('cta_label')->label('Button label')
            ->visibleIf(['cta_enabled' => true]),                       // DSL shortcut
        Text::make('cta_note')->label('Note')
            ->visible(fn (Get $get): bool => (bool) $get('cta_enabled')), // native closure
    ];
}

Use Group to break a long form into labelled clusters — see Layout & Structure.

Blocks ​

A block is a repeatable child item (a nav link, a pricing plan, a quote). Declare them with Block::make('slug'), each with its own settings schema and an optional limit:

php
use FilamentCraft\Sections\Block;
use FilamentCraft\Settings\Types\Text;
use FilamentCraft\Settings\Types\Link;

public static function blocks(): array
{
    return [
        Block::make('nav-link')
            ->name('Nav link')
            ->limit(6)
            ->settings([
                Text::make('label')->label('Label')->default('Page'),
                Link::make('url')->label('URL')->default('/'),
            ]),
    ];
}

Read blocks in the Blade view from $section->blocks. The maxBlocks() cap (default 16) limits the total number of blocks added to one section instance, across every block type.

Presets ​

The Browse presets modal
The Hero section's two presets — SaaS Spotlight and Editorial Split — in the Browse presets modal.

A preset is a named bundle of settings and blocks the editor can apply in one click. Return Preset objects from presets():

php
use FilamentCraft\Sections\Preset;

public static function presets(): array
{
    return [
        Preset::make('split-header', 'Split Header')
            ->settings([
                'brand_text' => 'Acme',
                'cta_enabled' => true,
            ])
            ->blocks([
                ['id' => 'nav-1', 'type' => 'nav-link', 'settings' => ['label' => 'Product', 'url' => '/product']],
                ['id' => 'nav-2', 'type' => 'nav-link', 'settings' => ['label' => 'Pricing', 'url' => '/pricing']],
            ]),
    ];
}

In the editor, presets surface behind the Browse presets button on the section's header — each one is a one-click starting point.

Registering a section ​

Two ways — both are calls on the plugin instance in your panel provider:

php
use FilamentCraft\FilamentCraftPlugin;

public function panel(Panel $panel): Panel
{
    return $panel->plugin(
        FilamentCraftPlugin::make()
            ->registerSection(\App\Sections\TestimonialSection::class)
            // …or auto-discover a whole directory:
            ->discoverSectionsIn(app_path('Sections'))
    );
}

The conventional path app/Sections/ is auto-scanned with no extra config.

Extending a built-in section ​

The bundled sections are intentionally subclassable. Give the subclass its own slug, optionally point it at a custom view, and override only what you want to change:

php
namespace App\Sections;

use FilamentCraft\Sections\Builtin\HeroSection;

class ProductHeroSection extends HeroSection
{
    protected static string $view = 'sections.product-hero';

    public static function slug(): string
    {
        return 'product-hero';
    }

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

Register the subclass with ->registerSection(ProductHeroSection::class). It inherits the parent's settings, blocks, and presets unless you override those methods too.

Proprietary — distributed via Anystack.