There are several ways to render Layup content outside the built-in frontend routes.
The @layup directive
Render any content array in a Blade template:
@layup($page->content)
This is the simplest approach. It instantiates LayupContent, walks the content tree, and renders all rows, columns, and widgets.
The LayupContent class
Use the helper class directly. It implements Htmlable:
use Crumbls\Layup\Support\LayupContent;
{{ new LayupContent($model->field) }}
The <x-layup-widget> component
Render a single widget outside the page builder:
<x-layup-widget type="button" :data="['label' => 'Sign Up', 'url' => '/register']" />
<x-layup-widget type="testimonial" :data="$testimonialData" />
This resolves the widget from the registry, applies Design/Advanced tab defaults, and renders the widget's Blade view. Unknown types render nothing and log a warning.
The HasLayupContent trait
Add Layup rendering to any Eloquent model with a JSON content column:
use Crumbls\Layup\Concerns\HasLayupContent;
class Post extends Model
{
use HasLayupContent;
protected string $layupContentColumn = 'body'; // default: 'content'
protected function casts(): array
{
return ['body' => 'array'];
}
}
Then render in Blade:
{!! $post->toHtml() !!}
The trait provides:
| Method | Returns | Description |
|---|---|---|
toHtml() |
string |
Render content to HTML |
getSectionTree() |
array |
Sections with hydrated Row/Column/Widget objects |
getContentTree() |
array |
Flat list of Row objects |
getUsedClasses() |
array |
Tailwind classes used in content |
getUsedInlineStyles() |
array |
Inline styles used in content |
WidgetData in Blade views
Use the WidgetData value object for typed, null-safe access in widget Blade templates:
@php $d = \Crumbls\Layup\Support\WidgetData::from($data); @endphp
<h1>{{ $d->string('heading') }}</h1>
<img src="{{ $d->storageUrl('background_image') }}" alt="{{ $d->string('alt') }}" />
@if($d->bool('show_overlay'))
<div style="opacity: {{ $d->float('overlay_opacity', 0.5) }}"></div>
@endif
Available methods: string(), bool(), int(), float(), array(), has(), storageUrl(), url(), toArray(). Implements ArrayAccess for backward compatibility.
Multiple dashboards
To use Layup across multiple Filament panels with separate page tables, override the model:
// config/layup.php
'pages' => [
'model' => \App\Models\PageB::class,
],
namespace App\Models;
class PageB extends \Crumbls\Layup\Models\Page
{
protected $table = 'custom_pages';
}
Render isolation
Broken widgets do not crash entire pages. If a widget throws an exception during rendering, it is caught and logged. In debug mode, an HTML comment shows the error. In production, the widget is silently skipped.
Contributors
Thank you to everyone who has contributed to this package. Every pull request, bug report, and idea makes a difference.