← All Packages /

Layup Page Builder

Choose your install path

Layup is a Filament form field first; the bundled Pages resource is a turnkey example built on top of it. Pick the path that fits how you plan to use it.

Path A -- Use Layup as a field on your own model. Skip the Pages resource. You bring the model, the JSON column, and your own Filament resource. Layup gives you the editor canvas. Continue at Field-only installation, then read Embedding the field.

Path B -- Use the bundled Pages resource. A full page CMS with nested pages, scheduled publishing, SEO meta, and frontend routes -- ready to use after php artisan layup:install. Continue below.

Either way, the field looks like this:

use Crumbls\Layup\Forms\Components\LayupBuilder;

LayupBuilder::make('content')->columnSpanFull()

Requirements

  • PHP 8.3+
  • Laravel 12+
  • Filament 5
  • Livewire 4

Prerequisites

Layup requires a working Filament installation. If you have not set up Filament yet:

composer require filament/filament
php artisan filament:install --panels

See the Filament installation docs for details.

Install via Composer

composer require crumbls/layup

Register the plugin

Add LayupPlugin to your Filament panel provider (e.g., app/Providers/Filament/AdminPanelProvider.php):

use Crumbls\Layup\LayupPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugins([
            LayupPlugin::make(),
        ]);
}

Registering the plugin makes the LayupBuilder field available in any Filament form and (unless disabled in config) registers the Pages resource in your sidebar.

Quick install (recommended)

Run the install command to handle everything in one step:

php artisan layup:install

This:

  • Publishes the config file
  • Runs database migrations (creates layup_pages and layup_page_revisions)
  • Creates a storage symlink (storage:link) so uploaded images are web-accessible
  • Creates the frontend layout component if it does not exist
  • Publishes Filament assets (CSS)
  • Generates the Tailwind safelist
  • Checks your setup and warns about any issues

After running install, skip to Tailwind safelist setup.

Manual installation

If you prefer to run each step yourself:

php artisan vendor:publish --tag=layup-config
php artisan migrate
php artisan storage:link
php artisan filament:assets
php artisan layup:safelist

This creates two tables: layup_pages (configurable name) and layup_page_revisions.

Tailwind safelist setup

Layup dynamically generates CSS classes for column widths, spacing, and user-defined styles. Tailwind needs to know about these classes.

Tailwind v4

Add to your CSS entry point:

@source "../../storage/layup-safelist.txt";

Tailwind v3

Add to your tailwind.config.js:

module.exports = {
    content: [
        // ...
        './storage/layup-safelist.txt',
    ],
};

Generate the safelist file (if you did not use layup:install):

php artisan layup:safelist

When safelist.auto_sync is enabled in config (the default), the safelist regenerates automatically every time a page is saved.

Build pipeline integration

Add the safelist command to your build script so it always runs before Tailwind compiles:

{
    "scripts": {
        "build": "php artisan layup:safelist && vite build"
    }
}

Rebuild frontend assets

npm run build

Without the safelist and rebuild steps, the page builder will work in the admin panel but frontend pages will have broken or missing styling.

Publish assets (optional)

Tag Command Description
layup-config php artisan vendor:publish --tag=layup-config Config file
layup-views php artisan vendor:publish --tag=layup-views Blade templates
layup-routes php artisan vendor:publish --tag=layup-routes Route file
layup-scripts php artisan vendor:publish --tag=layup-scripts Alpine.js components
layup-templates php artisan vendor:publish --tag=layup-templates Page templates
layup-translations php artisan vendor:publish --tag=layup-translations Language files
layup-stubs php artisan vendor:publish --tag=layup-stubs Widget scaffold stubs

Verify installation

Run the health check command to confirm everything is set up correctly:

php artisan layup:doctor

Then visit /admin/pages (or your panel path) and create a new page. You should see the visual builder with rows, columns, and the widget picker.

Troubleshooting

php artisan layup:doctor runs a battery of checks and prints passed / warning / failure counts. Below are the failures you are most likely to hit and how to fix each.

"LayupPlugin is not registered in any Filament panel"

The LayupPlugin::make() call is missing from your panel provider. Add it under ->plugins([...]) (see Register the plugin). After editing, clear the config cache: php artisan config:clear.

"Table 'layup_pages' does not exist"

Migrations have not run. Run:

php artisan migrate

If you are intentionally on the field-only path and do not want these tables, see Field-only installation -- the doctor warning is expected there.

"Storage symlink missing"

Uploaded images will not be web-accessible. Run:

php artisan storage:link

"Layout component [app] not found"

Layup expects a Blade component matching frontend.layout (default: app) to exist at resources/views/components/app.blade.php. Either:

  • Run php artisan layup:install -- it copies a starter layout component if one is missing, or
  • Create the component manually, or
  • Set frontend.layout in config/layup.php to point to your existing layout component (e.g., 'layouts.app' for resources/views/components/layouts/app.blade.php).

"Layout does not include @layupScripts"

Interactive widgets (accordion, tabs, countdown, modals, slider, etc.) will not function without this directive. Add it to your frontend layout, typically just before the closing </body> tag:

@layupScripts
</body>

"Safelist file does not exist" / Frontend pages render without styling

Tailwind cannot see Layup's dynamically-generated classes. Verify three things in order:

  1. The safelist file exists -- run php artisan layup:safelist to generate it.
  2. Your Tailwind config or CSS entry point references the safelist path (see Tailwind safelist setup).
  3. You ran npm run build (or your equivalent) after adding the safelist reference.

"Upload disk 'public' is not configured"

Your config/filesystems.php does not have a disk matching uploads.disk. Either configure the disk or set uploads.disk in config/layup.php to a disk you do have configured.

If a check is not listed here, run php artisan layup:doctor and read the message inline -- each failure includes a one-line fix hint.

Upgrades

See CHANGELOG.md for release notes, breaking changes, and version-by-version migration guidance.


Contributors

Thank you to everyone who has contributed to this package. Every pull request, bug report, and idea makes a difference.