← All plugins

MoonShine Advanced

Made by the authors of MoonShine

MoonShine Advanced is a Laravel package that enhances MoonShine with advanced components like multi-step forms, async tabs, and custom input groups, ideal for building dynamic admin panels. It supports Laravel 10+, PHP 8.1+, and offers features like step locking, event handling, and customizable UI elements.

Rating
Downloads
2581
Version
2.0.0
Last updated
21.01.2026
MoonShine version
v3
Github stars
13
MoonShine Software
Author
MoonShine Software

logo

MoonShine Advanced

Advanced Fields and Components

Tests status Total Downloads Latest Stable Version License

Laravel 10+ PHP 8.1+

composer require moonshine/advanced
composer require moonshine/advanced

Stepper

Basic:

use MoonShine\Advanced\Components\Stepper\Stepper;
use MoonShine\Advanced\Components\Stepper\Step;
Stepper::make([
Step::make([
Heading::make('Step 1 content')
], 'Step 1', 'Some description'),
Step::make([
FormBuilder::make()
], 'Step 2', 'Some description'),
Step::make([
// any components
], 'Step 3', 'Some description'),
])
use MoonShine\Advanced\Components\Stepper\Stepper;
use MoonShine\Advanced\Components\Stepper\Step;
Stepper::make([
Step::make([
Heading::make('Step 1 content')
], 'Step 1', 'Some description'),
Step::make([
FormBuilder::make()
], 'Step 2', 'Some description'),
Step::make([
// any components
], 'Step 3', 'Some description'),
])

Async content:

Stepper::make([
Step::make(title: 'Step', description: 'Some description')->async('/html')
])
Stepper::make([
Step::make(title: 'Step', description: 'Some description')->async('/html')
])

Also with events:

Stepper::make([
Step::make(title: 'Step', description: 'Some description')->async('/html', events: [
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-1')
])
])
Stepper::make([
Step::make(title: 'Step', description: 'Some description')->async('/html', events: [
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-1')
])
])

Events when switching a step

Events when a step is changing:

Step::make(title: 'Step', description: 'Some description')
->whenChangingEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-2')
], once: false)
Step::make(title: 'Step', description: 'Some description')
->whenChangingEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-2')
], once: false)

Events when a step is completed:

Step::make(title: 'Step', description: 'Some description')
->whenFinishEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-2')
], once: true)
Step::make(title: 'Step', description: 'Some description')
->whenFinishEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'fragment-2')
], once: true)

The once parameter indicates once the events will be caused or with each change

Content after completion

When all the steps are completed, this set of components will be displayed on the page

Stepper::make([
// ...
], finishComponent: [
Heading::make('Thanks!')
]),
Stepper::make([
// ...
], finishComponent: [
Heading::make('Thanks!')
]),

The names of the buttons

Stepper::make([
// ...
], nextText: 'Next step', finishText: 'Finish'),
Stepper::make([
// ...
], nextText: 'Next step', finishText: 'Finish'),

Modifying the button next step

Stepper::make([
// ...
])->changeNextButton(function(ActionButton $btn, int $index) {
return $btn->badge($index);
}),
Stepper::make([
// ...
])->changeNextButton(function(ActionButton $btn, int $index) {
return $btn->badge($index);
}),

States

Active default step

Stepper::make([
// ...
])->current(2),
Stepper::make([
// ...
])->current(2),

Completed by default

Stepper::make([
// ...
])->finished(),
Stepper::make([
// ...
])->finished(),

Locking

You cannot go to the next step, you can switch to the next Schag only using the event (go_to_step_ {index}: {stPper_name})

Step::make()->nextLock(),
Step::make()->nextLock(),

The transition in the upper navigation is blocked:

Stepper::make([
// ...
])->lock(),
Stepper::make([
// ...
])->lock(),

Once all steps are completed, the top navigation is locked:

Stepper::make([
// ...
])->lockWhenFinish(),
Stepper::make([
// ...
])->lockWhenFinish(),

Async tabs

use MoonShine\Advanced\Components\AsyncTabs\AsyncTabs;
use MoonShine\Advanced\Components\AsyncTabs\AsyncTab;
AsyncTabs::make([
AsyncTab::make('Tab 1', '/html'),
AsyncTab::make('Tab 2', '/html')->icon('users'),
]),
use MoonShine\Advanced\Components\AsyncTabs\AsyncTabs;
use MoonShine\Advanced\Components\AsyncTabs\AsyncTab;
AsyncTabs::make([
AsyncTab::make('Tab 1', '/html'),
AsyncTab::make('Tab 2', '/html')->icon('users'),
]),

Link group

use MoonShine\Advanced\Components\LinkGroup\LinkGroup;
use MoonShine\Advanced\Components\LinkGroup\LinkItem;
LinkGroup::make([
LinkItem::make('/documentation', 'Documentation', 'Some description')->icon('arrow-right'),
// ...
]),
use MoonShine\Advanced\Components\LinkGroup\LinkGroup;
use MoonShine\Advanced\Components\LinkGroup\LinkItem;
LinkGroup::make([
LinkItem::make('/documentation', 'Documentation', 'Some description')->icon('arrow-right'),
// ...
]),

Radio group

use MoonShine\Advanced\Fields\RadioGroup;
RadioGroup::make('Sex')->options([
1 => 'Male',
2 => 'Female',
])->inline(),
use MoonShine\Advanced\Fields\RadioGroup;
RadioGroup::make('Sex')->options([
1 => 'Male',
2 => 'Female',
])->inline(),

Checkbox list

use MoonShine\Advanced\Fields\CheckboxList;
CheckboxList::make('Plan')->options([
1 => 'Basic',
2 => 'Standard',
3 => 'Pro',
])->inline(),
use MoonShine\Advanced\Fields\CheckboxList;
CheckboxList::make('Plan')->options([
1 => 'Basic',
2 => 'Standard',
3 => 'Pro',
])->inline(),

Button group

use MoonShine\Advanced\Fields\ButtonGroup;
ButtonGroup::make('Plan')->options([
1 => 'Basic',
2 => 'Standard',
3 => 'Pro',
])->multiple(),
use MoonShine\Advanced\Fields\ButtonGroup;
ButtonGroup::make('Plan')->options([
1 => 'Basic',
2 => 'Standard',
3 => 'Pro',
])->multiple(),

SPA Menu

use MoonShine\MenuManager\MenuItem;
protected function menu(): array
{
return [
MenuItem::make('Users', UserResource::class)->spa(),
];
}
use MoonShine\MenuManager\MenuItem;
protected function menu(): array
{
return [
MenuItem::make('Users', UserResource::class)->spa(),
];
}

Example

public function stepForm(MoonShineRequest $request): MoonShineJsonResponse
{
$request->validate([
'name' => ['required'],
'email' => ['required'],
]);
return MoonShineJsonResponse::make()->events([
'go_to_step_2:dashboard'
]);
}
protected function components(): iterable
{
return [
Stepper::make([
Step::make([
FormBuilder::make()
->name('step_1_form')
->asyncMethod('stepForm')
->fields([
Grid::make([
Column::make([
Box::make([
Text::make('Name'),
Email::make('Email'),
RadioGroup::make('Sex')->options([
1 => 'Male',
2 => 'Female',
])->inline(),
])
])->columnSpan(6),
Column::make([
Box::make([
CheckboxList::make('Job title')->options([
1 => 'Developer',
2 => 'Team lead',
]),
ButtonGroup::make('Plan')->options([
1 => 'Free',
2 => 'Basic',
3 => 'Pro',
]),
])
])->columnSpan(6)
])
])
->hideSubmit()
], 'Step 1', 'Tell us about yourself')->nextLock()->whenChangingEvents([
AlpineJs::event(JsEvent::FORM_SUBMIT, 'step_1_form')
]),
Step::make([
AsyncTabs::make([
AsyncTab::make('How to use the project', '/html'),
AsyncTab::make('User agreement', '/html'),
]),
], 'Step 2', 'Rules')->icon('users'),
Step::make([], 'Step 3', 'Finishing')->async('/html', events: [
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'time')
])->whenFinishEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'time')
]),
], [
Heading::make('Thanks!'),
LinkGroup::make([
LinkItem::make('#', 'Link 1', 'Description 1')->icon('arrow-right'),
LinkItem::make('#', 'Link 2'),
])
], 'Next', 'Finish')->name('dashboard')->lock(),
Fragment::make([
time()
])->name('time'),
];
}
public function stepForm(MoonShineRequest $request): MoonShineJsonResponse
{
$request->validate([
'name' => ['required'],
'email' => ['required'],
]);
return MoonShineJsonResponse::make()->events([
'go_to_step_2:dashboard'
]);
}
protected function components(): iterable
{
return [
Stepper::make([
Step::make([
FormBuilder::make()
->name('step_1_form')
->asyncMethod('stepForm')
->fields([
Grid::make([
Column::make([
Box::make([
Text::make('Name'),
Email::make('Email'),
RadioGroup::make('Sex')->options([
1 => 'Male',
2 => 'Female',
])->inline(),
])
])->columnSpan(6),
Column::make([
Box::make([
CheckboxList::make('Job title')->options([
1 => 'Developer',
2 => 'Team lead',
]),
ButtonGroup::make('Plan')->options([
1 => 'Free',
2 => 'Basic',
3 => 'Pro',
]),
])
])->columnSpan(6)
])
])
->hideSubmit()
], 'Step 1', 'Tell us about yourself')->nextLock()->whenChangingEvents([
AlpineJs::event(JsEvent::FORM_SUBMIT, 'step_1_form')
]),
Step::make([
AsyncTabs::make([
AsyncTab::make('How to use the project', '/html'),
AsyncTab::make('User agreement', '/html'),
]),
], 'Step 2', 'Rules')->icon('users'),
Step::make([], 'Step 3', 'Finishing')->async('/html', events: [
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'time')
])->whenFinishEvents([
AlpineJs::event(JsEvent::FRAGMENT_UPDATED, 'time')
]),
], [
Heading::make('Thanks!'),
LinkGroup::make([
LinkItem::make('#', 'Link 1', 'Description 1')->icon('arrow-right'),
LinkItem::make('#', 'Link 2'),
])
], 'Next', 'Finish')->name('dashboard')->lock(),
Fragment::make([
time()
])->name('time'),
];
}