Package development

# Basics

MoonShine is based on Laravel packages. If you're new to Laravel package development, here are some resources to help you understand the basic concepts:

# ServiceProvider

Through the ServiceProvider of your package, you can automatically add resources, pages, create menus and authorization rules, and much more.

namespace Author\MoonShineMyPackage;
use Illuminate\Support\ServiceProvider;
class MyPackageServiceProvider extends ServiceProvider
public function boot(): void
new MyPackageResource(),
new MyPackagePage(),
MenuItem::make('MyPage', new MyPackagePage())

Also you can interact with AssetManager or ColorManager

public function boot(): void
public function boot(): void

If you need to add additional authorization logic in an application or in an external package, then use the method defineAuthorization.

public function boot(): void
static function (ResourceContract $resource, Model $user, string $ability): bool {
return true;

Don't forget to automatically connect your ServiceProvider in composer.json

"extra": {
"laravel": {
"providers": [

# Custom field example

Let's take a quick look at creating your own field! This will be a visual editor based on the Quill js plugin

Let's create a field using the moonshine:field command and select that it extends Textarea

php artisan moonshine:field Quill

Let's remove unnecessary methods and add css/js

namespace App\MoonShine\Fields;
use MoonShine\Fields\Textarea;
final class Quill extends Textarea
protected string $view = 'moonshine-quill::fields.quill';
protected array $assets = [
'/css/moonshine/quill/quill.snow.css', // theme
'/js/moonshine/quill/quill.js', // lib
'/js/moonshine/quill/quill-init.js', // init

Let's also change the view fields

<div x-data="quill">
<div class="ql-editor" :id="$id('quill')" style="height: auto;">{!! $value ?? '' !!}</div>
'class' => 'ql-textarea',
'name' => $element->name(),
'style' => 'display: none;'
>{!! $value ?? '' !!}</x-moonshine::form.textarea>

We took quill.snow.css and quill.js from the library, but js initialization using alpineJs is presented below

document.addEventListener('alpine:init', () => {'quill', () => ({
textarea: null,
editor: null,
init() {
this.textarea = this.$root.querySelector('.ql-textarea')
this.editor = this.$root.querySelector('.ql-editor')
const t = this
this.$nextTick(function() {
let quill = new Quill(`#${}`, {
theme: 'snow'
quill.on('text-change', () => {
t.textarea.value = t.editor.innerHTML || '';
t.textarea.dispatchEvent(new Event('change'));

An example of placing this field in a separate package can be found in the repository