Basics
The Offcanvas component allows you to create side panels.
You can create an Offcanvas using the static method make().
make(Closure|string $title = '',Closure|Renderable|string $content = '',Closure|string $toggler = '',Closure|string|null $asyncUrl = null,iterable $components = [],)make(Closure|string $title = '',Closure|Renderable|string $content = '',Closure|string $toggler = '',Closure|string|null $asyncUrl = null,iterable $components = [],)
$title- the title of the side panel,$content- the content of the side panel,$toggler- the title for the button,$asyncUrl- the URL for asynchronous content,$components- components
use MoonShine\UI\Components\OffCanvas;OffCanvas::make('Confirm',static fn() => FormBuilder::make(route('password.confirm'))->async()->fields([Password::make('Password')->eye(),])->submit('Confirm'),'Show Panel')
use MoonShine\UI\Components\OffCanvas;OffCanvas::make('Confirm',static fn() => FormBuilder::make(route('password.confirm'))->async()->fields([Password::make('Password')->eye(),])->submit('Confirm'),'Show Panel')
<x-moonshine::off-canvastitle="Offcanvas":left="false"><x-slot:toggler>Open</x-slot:toggler>Content</x-moonshine::off-canvas><x-moonshine::off-canvastitle="Offcanvas":left="false"><x-slot:toggler>Open</x-slot:toggler>Content</x-moonshine::off-canvas>
The content parameter refers to the textual content of OffCanvas. It's suitable for displaying simple information (strings, HTML, etc.).
However, if you want to embed components into OffCanvas — such as fields or forms that respond to value changes or rely on reactivity —
it’s important to understand that MoonShine won’t be able to “see” components passed as plain strings.
This limits functionality.
To ensure MoonShine properly handles fields inside OffCanvas, you should pass them using the components parameter.
If you're building the content of OffCanvas entirely with MoonShine components (fields, forms, etc.), use the components parameter instead of content.
Events
You can trigger the opening/closing of the sidebar from outside the component via javascript events.
To access the events, you need to set a unique name for the side panel using the name() method.
protected function components(): iterable{return [Offcanvas::make('Title','Content...')->name('my-canvas')];}protected function components(): iterable{return [Offcanvas::make('Title','Content...')->name('my-canvas')];}
Triggering Event via ActionButton
The side panel event can be triggered using the ActionButton component.
Offcanvas::make('Title','Content...',)->name('my-canvas'),ActionButton::make('Show Modal')->toggleOffCanvas('my-canvas')// or asyncActionButton::make('Show Panel','/endpoint')->async(events: [AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'my-canvas')])Offcanvas::make('Title','Content...',)->name('my-canvas'),ActionButton::make('Show Modal')->toggleOffCanvas('my-canvas')// or asyncActionButton::make('Show Panel','/endpoint')->async(events: [AlpineJs::event(JsEvent::OFF_CANVAS_TOGGLED, 'my-canvas')])
Triggering Event Using Native Methods
Events can be triggered using native JavaScript methods:
document.addEventListener("DOMContentLoaded", () => {this.dispatchEvent(new CustomEvent("off_canvas_toggled:my-canvas"))})document.addEventListener("DOMContentLoaded", () => {this.dispatchEvent(new CustomEvent("off_canvas_toggled:my-canvas"))})
Triggering Event Using Alpine.js Method
Or use the magic method $dispatch() from Alpine.js:
this.$dispatch('off_canvas_toggled:my-canvas')this.$dispatch('off_canvas_toggled:my-canvas')
Triggering Event Using Global MoonShine Class
MoonShine.ui.toggleOffCanvas('my-canvas')MoonShine.ui.toggleOffCanvas('my-canvas')
Events when opening/closing
You can also add events when opening/closing the side panel using the toggleEvents() method.
toggleEvents(array $events,bool $onlyOpening = false,bool $onlyClosing = false)toggleEvents(array $events,bool $onlyOpening = false,bool $onlyClosing = false)
$events- events,$onlyOpening- will only fire when opening,$onlyClosing- will only fire when closing.
ActionButton::make('Open off-canvas')->toggleOffCanvas('my-off-canvas'),OffCanvas::make('My OffCanvas', asyncUrl: '/')->name('my-off-canvas')->toggleEvents([AlpineJs::event(JsEvent::TOAST,params: ['text' => 'Hello off-canvas'])]),ActionButton::make('Open off-canvas')->toggleOffCanvas('my-off-canvas'),OffCanvas::make('My OffCanvas', asyncUrl: '/')->name('my-off-canvas')->toggleEvents([AlpineJs::event(JsEvent::TOAST,params: ['text' => 'Hello off-canvas'])]),
Default State
The open() method allows you to show the side panel on page load.
open(Closure|bool|null $condition = null)open(Closure|bool|null $condition = null)
OffCanvas::make('Title', 'Content...', 'Show Panel')->open()OffCanvas::make('Title', 'Content...', 'Show Panel')->open()
By default, the side panel will be hidden on page load.
Position
By default, the side panel is positioned on the right side of the screen; the left() method allows you to position the panel on the left side.
left(Closure|bool|null $condition = null)left(Closure|bool|null $condition = null)
OffCanvas::make('Title', 'Content...', 'Show Panel')->left()OffCanvas::make('Title', 'Content...', 'Show Panel')->left()
Width
The wide() method of the OffCanvas component allows you to make the panel wider.
wide(Closure|bool|null $condition = null)wide(Closure|bool|null $condition = null)
$condition- method execution condition.
OffCanvas::make('Title', 'Content...', 'Show Panel')->wide()OffCanvas::make('Title', 'Content...', 'Show Panel')->wide()
The full() method sets the maximum width for the panel.
full(Closure|bool|null $condition = null)full(Closure|bool|null $condition = null)
$condition- method execution condition.
OffCanvas::make('Title', 'Content...', 'Show Panel')->full()OffCanvas::make('Title', 'Content...', 'Show Panel')->full()
Asynchronous
OffCanvas::make('Title', '', 'Show Panel', asyncUrl: '/endpoint'),OffCanvas::make('Title', '', 'Show Panel', asyncUrl: '/endpoint'),
The request will be sent only once, but if you need to send the request each time it opens, use the alwaysLoad() method.
OffCanvas::make(...)->alwaysLoad(),OffCanvas::make(...)->alwaysLoad(),
Auto Close
By default, OffCanvas closes after the asynchronous form inside it has been successfully submitted.
The autoClose() method allows you to control this behavior.
autoClose(Closure|bool|null $autoClose = null)autoClose(Closure|bool|null $autoClose = null)
OffCanvas::make('Demo OffCanvas',static fn() => FormBuilder::make(route('alert.post'))->fields([Text::make('Text'),])->submit('Submit', ['class' => 'btn-primary'])->async(),)->name('demo-offcanvas')->autoClose(false),OffCanvas::make('Demo OffCanvas',static fn() => FormBuilder::make(route('alert.post'))->fields([Text::make('Text'),])->submit('Submit', ['class' => 'btn-primary'])->async(),)->name('demo-offcanvas')->autoClose(false),
Auto Close
By default, off-canvas panels close after a successful request (for example, when submitting a form).
The autoClose() method allows you to control this behavior.
autoClose(Closure|bool|null $autoClose = null)autoClose(Closure|bool|null $autoClose = null)
OffCanvas::make('Title',static fn() => FormBuilder::make(route('endpoint'))->fields([Text::make('Text'),])->submit('Submit', ['class' => 'btn-primary'])->async(),'Show Panel')->autoClose(false),OffCanvas::make('Title',static fn() => FormBuilder::make(route('endpoint'))->fields([Text::make('Text'),])->submit('Submit', ['class' => 'btn-primary'])->async(),'Show Panel')->autoClose(false),
Toggler Attributes
The togglerAttributes() method allows you to set additional attributes for the toggler $toggler.
togglerAttributes(array $attributes)togglerAttributes(array $attributes)
OffCanvas::make('Title', 'Content...', 'Show Panel')->togglerAttributes(['class' => 'mt-2']),OffCanvas::make('Title', 'Content...', 'Show Panel')->togglerAttributes(['class' => 'mt-2']),