PHPackages                             guava/tutorials - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. guava/tutorials

ActiveLibrary

guava/tutorials
===============

1.1.0(1y ago)559.2k—0%9[3 issues](https://github.com/GuavaCZ/tutorials/issues)[1 PRs](https://github.com/GuavaCZ/tutorials/pulls)MITPHP

Since Oct 10Pushed 1y ago2 watchersCompare

[ Source](https://github.com/GuavaCZ/tutorials)[ Packagist](https://packagist.org/packages/guava/tutorials)[ GitHub Sponsors](https://github.com/GuavaCZ)[ RSS](/packages/guava-tutorials/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (5)Dependencies (5)Versions (8)Used By (0)

[![Guava Tutorials Banner](https://github.com/GuavaCZ/tutorials/raw/alpha/docs/images/banner.jpg)](https://github.com/GuavaCZ/tutorials/raw/alpha/docs/images/banner.jpg)

### Tutorials

[](#tutorials)

Tutorials is a complete tool for creating tutorials, walkthroughs and onboarding experiences for your users. It is a simple and easy to use library, which can be integrated into your project with just a few lines of code.

### Not ready for production!

[](#not-ready-for-production)

The tutorials plugin is currently in alpha version and thus not production-ready. Use at your own risk.

Showcase
--------

[](#showcase)

[![Screenshot 1](https://github.com/GuavaCZ/tutorials/raw/main/docs/images/screenshot_01.png)](https://github.com/GuavaCZ/tutorials/raw/main/docs/images/screenshot_01.png)[![Screenshot 2](https://github.com/GuavaCZ/tutorials/raw/main/docs/images/screenshot_02.png)](https://github.com/GuavaCZ/tutorials/raw/main/docs/images/screenshot_02.png)

[Video Showcase 1](https://github.com/GuavaCZ/tutorials/blob/main/docs/videos/screencast_01.mov)[Video Showcase 2](https://github.com/GuavaCZ/tutorials/blob/main/docs/videos/screencast_02.mov)

Support us
----------

[](#support-us)

Your support is key to the continual advancement of our plugin. We appreciate every user who has contributed to our journey so far.

While our plugin is available for all to use, if you are utilizing it for commercial purposes and believe it adds significant value to your business, we kindly ask you to consider supporting us through GitHub Sponsors. This sponsorship will assist us in continuous development and maintenance to keep our plugin robust and up-to-date. Any amount you contribute will greatly help towards reaching our goals. Join us in making this plugin even better and driving further innovation.

#### Prerequisites

[](#prerequisites)

- Laravel 10+
- PHP 8.0+
- Filament 3
- Livewire 3

Filament is currently a prerequisite, but it can be also used outside of the Filament Panels anywhere in your frontend in any livewire component.

Documentation
=============

[](#documentation)

Below is all the information you need to get started. We try to follow the Filament conventions as much as possible, so a lot of these steps should be familiar to you already.

Installation
------------

[](#installation)

```
composer require guava/tutorials
```

### Add assets to your theme

[](#add-assets-to-your-theme)

You will require a custom theme to use this plugin. In your theme's `tailwind.config.js` file, add the following to your content array:

```
export default {
    presets: [preset],
    content: [
        // ...
        './vendor/guava/tutorials/resources/**/*.php',
    ],
}
```

### Add plugin to your filament dashboard

[](#add-plugin-to-your-filament-dashboard)

```
use Guava\Tutorials\TutorialsPlugin;

$panel->plugins([
    TutorialsPlugin::make(),
    //
])
```

### Add tutorials to your livewire component (or filament page)

[](#add-tutorials-to-your-livewire-component-or-filament-page)

To get started, you need to do the following:

1. Implement the `HasTutorials` interface and use the `InteractsWithTutorials` trait.
2. Implement the `tutorial()` function.
3. Configure your tutorial inside the `tutorial()` function.
4. Mount the tutorial in the `mount()` function using `mountTutorial()`.

Let's say we have a Project Resource that allows us to edit the `name` and `description` of the project. And when creating a project, we want to guide the user through the process using a tutorial. This is how our final create page class would look like:

```
use Guava\Tutorials\Concerns\InteractsWithTutorials;
use Guava\Tutorials\Contracts\HasTutorials;
use Guava\Tutorials\Steps\Step;

class CreateProject extends CreateRecord implements HasTutorials
{
    use InteractsWithTutorials;

    public function mount(): void
    {
        parent::mount();

        $this->mountTutorial();
    }

    public function tutorial(Tutorial $tutorial) : Tutorial
    {
        return $tutorial->steps([
            Step::make('name'),
            Step::make('description'),
        ]);
    }
}
```

That's it! You just created your first tutorial.

Keep in mind that this tutorial will be mounted on each page load. It is up to you to define the logic of when to mount the tutorial.

### Tutorials

[](#tutorials-1)

A tutorial is a set of `Steps` that should guide the user through your livewire components (or filament pages).

### Tutorial Lifecycle

[](#tutorial-lifecycle)

You can hook into different parts of a Tutorial`s lifecycle.

#### After mount

[](#after-mount)

After a tutorial is mounted, you can call your own code:

```
$tutorial->steps([
    //
])
->afterMount(
    fn() => // Your code here
)
```

#### After unmount

[](#after-unmount)

After a tutorial is unmounted, you can call your own code:

```
$tutorial->steps([
    //
])
->afterUnmount(
    fn() => // Your code here
)
```

#### After Skipped

[](#after-skipped)

If you have skippable tutorials, you can call your own code after a tutorial was skipped:

```
$tutorial->steps([
    //
])
->afterSkipped(
    fn() => // Your code here
)
```

Steps
-----

[](#steps)

Each tutorial consists of `Steps`, where each step represents an action the user can make or a part they should draw their attention to. Such as `fill out a form field`, `click a button` or just `view a widget`.

A step is basically an overlay around your target (form field, action button, ...) with:

1. A label positioned in the top-left corner of the step overlay.
2. A hint positioned in the top-right corner of the step overlay. By default, hint shows the tutorial progress: current step and the total number of steps.
3. A description positioned in the bottom-left corner of the step.
4. And actions positioned in the bottom-right corner of the step.

Steps offer plenty of customization options, which we will try to describe below.

### Selector

[](#selector)

Every step needs a selector which is used to target an element to render an overlay around.

When a `Step` is created, it accepts either an instance of `Selector` or a `string` selector as a parameter.

When a `string` selector is passed, by default a `FormSelector`/`FieldSelector` (both are the same) is used.

But you are not limited to only targeting form fields, you can also target other elements on the page, such as a `Widget` or a `Action` button.

#### Form Field Selector

[](#form-field-selector)

This is the default selector used by a step.

```
use Guava\Tutorials\Selectors\FormSelector;
use Guava\Tutorials\Selectors\FieldSelector;
use Guava\Tutorials\Selectors\ComponentSelector;

// All variants are the same
Step::make('username');
Step::make(FormSelector::make('username'));
Step::make(FieldSelector::make('username'));
Step::make(ComponentSelector::make('username'));
```

All variants are the same, use whichever you prefer.

#### Widget Selector

[](#widget-selector)

Use this selector to target Widgets.

```
use Guava\Tutorials\Selectors\WidgetSelector;

// Currently only the "index" of the widget is supported
// So first widget = '1', second widget = '2', etc.
Step::make(WidgetSelector::make('1'));
```

#### (Generic) Selector

[](#generic-selector)

A generic selector can be used to target elements using a CSS selector, such as:

```
use \Guava\Tutorials\Selectors\Selector;

Step::make(Selector::make('div'));
Step::make(Selector::make('#my-id'));
Step::make(Selector::make('.my-class'));
Step::make(Selector::make('[data-attribute]'));
```

### Customizing label

[](#customizing-label)

By default the label is hidden. Here's how to set a label:

```
Step::make('username')
    ->label('Enter a username');
```

You can also conditionally hide the label using:

```
Step::make('username')
    ->hiddenLabel(true); // or a closure
```

### Customizing description

[](#customizing-description)

By default the description is hidden. Here's how to set a description:

```
Step::make('username')
    ->description('Pick an easy-to-remember, unique username');
```

You can also conditionally hide the description using:

```
Step::make('username')
    ->hiddenDescription(true); // or a closure
```

### Customizing hint

[](#customizing-hint)

By default the hint shows the tutorial's current progress in form of the current step number out of the total number of steps. You can override the step using:

```
Step::make('username')
    ->hint('Min. 6 characters');
```

You can also conditionally hide the hint using:

```
Step::make('username')
    ->hiddenHint(true); // or a closure
```

### Customizing color

[](#customizing-color)

By default, every step uses the `primary` color from your filament admin panel. You can however customize the color using:

```
Step::make('username')
    ->color('danger'); // or any other acceptable filament color parameter
```

### Pass through

[](#pass-through)

By default, a step has an overlay around it, but the user can still interact with the targeted element (form field, action button, ...).

If you want to prevent this, for example in a case where you only want to showcase something to the user without allowing them to interact with the element itself, you can disable event pass through using:

```
Step::make('username')
    ->passThrough(false);
```

This way they won't be able to interact with the targetted element.

### Intercepting clicks

[](#intercepting-clicks)

Similarly, you might have created a `Step` for an `Action` button that you want the user to click on to show what happens.

For example, you might have a button that when clicked, will generate a random username. And as part of the tutorial, you want the user to click the button, trigger it's function (generate the username) but **also proceed to the next step**.

This is where this feature comes in handy, as the click will also cause the tutorial to proceed to the next step.

You can add it to your step using:

```
Step::make('username')
    ->interceptClick();
```

### Customizing actions

[](#customizing-actions)

By default, the step makes use of all built-in actions.

To override these actions, you can use the following functions:

```
Step::make('username')
    ->nextStepAction(
        fn(NextStepAction $action) =>  // customize $action here
    )
    ->previousStepAction(
        fn(PreviousStepAction $action) =>  // customize $action here
    )
    ->skipTutorialAction(
        fn(SkipTutorialAction $action) =>  // customize $action here
    )
    ->completeTutorialAction(
        fn(CompleteTutorialAction $action) =>  // customize $action here
    );
```

You can also pass your own `TutorialAction` to these methods or pass `null` to disable the action.

For complete control over the actions rendered for the Step, you can use the `actions` function and pass an array of actions you want to render:

```
Step::make('username')
    ->actions([
        PreviousStepAction::make(),
        NextStepAction::make(),
        MyCustomAction::make(),
    ])
```

### Utility Injection

[](#utility-injection)

Almost every function also accepts a Closure as parameter. These closures inject a variety of utilities for you to use, described below.

#### Injecting the current record

[](#injecting-the-current-record)

If you want to access the record from a given `Step`:

```
use Illuminate\Database\Eloquent\Model;

function (?Model $record) {
    // ...
}
```

#### Injecting the current step

[](#injecting-the-current-step)

If you want to access the instance of the `Step` itself:

```
use Guava\Tutorials\Steps\Step;

function (Step $step) {
    // ...
}
```

#### Injecting the tutorial

[](#injecting-the-tutorial)

If you want to access the `Tutorial` instance that the `Step` belongs to:

```
use Guava\Tutorials\Tutorial;

function (Tutorial $tutorial) { // or $container
    // ...
}
```

#### Injecting the form component

[](#injecting-the-form-component)

If your Step targets a `Form field`, you can inject the form component instance:

```
use Filament\Forms\Components\Component;

function (Component $component) {
    // ...
}
```

#### Injecting the state of another form field

[](#injecting-the-state-of-another-form-field)

If your livewire component also contains a `Form`, you can access any form field's state using the `get` callback:

```
use Filament\Forms\Get;

function (Get $get) {
    // ...
}
```

#### Injecting the current Livewire component instance

[](#injecting-the-current-livewire-component-instance)

You can inject the current `Livewire component` instance using:

```
use Livewire\Component;

function (Component $livewire) {
    // ...
}
```

Actions
-------

[](#actions)

You can add multiple actions to a step to perform various tasks.

The plugin comes with a few built-in actions, such as:

1. NextStepAction: handles changing to the next step.
2. PreviousStepAction: handles changing to the previous step.
3. SkipTutorialAction: handles skipping the whole tutorial.
4. CompleteTutorialAction: handles completing the tutorial (last step).

Each of these actions are derived from `TutorialAction`, which you extend to create your own Actions if you'd like.

Actions have all the customization options like regular Filament actions. You can define the color, label, icon or conditionally hide them.

Using multiple tutorials
------------------------

[](#using-multiple-tutorials)

By default, the `InteractsWithTutorials` trait only handles one tutorial per Livewire component - `tutorial()`. To add more tutorials to the Livewire component, you can define them in the getTutorials() method, and return an array containing the name of each tutorial:

```
protected function getTutorials() : array
{
    return [
        'simpleTutorial',
        'advancedTutorial',
];
}
```

Each of these tutorials can now be defined within the Livewire component, using a method with the same name:

```
public function simpleTutorial(Tutorial $tutorial) : Tutorial
{
    $tutorial->steps([
        //
    ]);
}

public function advancedTutorial(Tutorial $tutorial) : Tutorial
{
    $tutorial->steps([
        //
    ]);
}
```

To mount a specific tutorial, simply pass the name of the tutorial in the `mountTutorial(string $name)` function, such as:

```
public function mount(): void
{
    parent::mount();

    $this->mountTutorial('simpleTutorial');
}
```

Again, it's completely up to you when you mount which tutorial.

Credits
-------

[](#credits)

- Guava
- All Contributors

Our documentation is highly inspired by the awesome Filament Documentation. Partly also because we tried to keep as close to the familiar Filament API as possible and a lot of things work the same.

###  Health Score

37

—

LowBetter than 83% of packages

Maintenance34

Infrequent updates — may be unmaintained

Popularity39

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 90.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~84 days

Total

5

Last Release

615d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/42d872f5f47cd71cfd46c8fbd6ec77a6bfb46d6d9499b5e1f843eb407c07f737?d=identicon)[Skrypt](/maintainers/Skrypt)

---

Top Contributors

[![lukas-frey](https://avatars.githubusercontent.com/u/10926334?v=4)](https://github.com/lukas-frey "lukas-frey (59 commits)")[![fsamapoor](https://avatars.githubusercontent.com/u/4992968?v=4)](https://github.com/fsamapoor "fsamapoor (3 commits)")[![Uolsen](https://avatars.githubusercontent.com/u/47712422?v=4)](https://github.com/Uolsen "Uolsen (3 commits)")

---

Tags

tutorial

###  Code Quality

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/guava-tutorials/health.svg)

```
[![Health](https://phpackages.com/badges/guava-tutorials/health.svg)](https://phpackages.com/packages/guava-tutorials)
```

###  Alternatives

[bezhansalleh/filament-shield

Filament support for `spatie/laravel-permission`.

2.8k2.9M88](/packages/bezhansalleh-filament-shield)[kirschbaum-development/commentions

A package to allow you to create comments, tag users and more

12369.2k](/packages/kirschbaum-development-commentions)[guava/calendar

Adds support for vkurko/calendar to Filament PHP.

298241.0k3](/packages/guava-calendar)[andreia/filament-ui-switcher

Add a modal with options to switch between different UI layouts and styles (colors, fonts, font sizes).

233.8k](/packages/andreia-filament-ui-switcher)[a2insights/filament-saas

Filament Saas for A2Insights

161.1k](/packages/a2insights-filament-saas)[joaopaulolndev/filament-world-clock

Show hours around the world by timezone

3111.9k](/packages/joaopaulolndev-filament-world-clock)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
