PHPackages                             capevace/livewire-optimistic-ui - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. capevace/livewire-optimistic-ui

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

capevace/livewire-optimistic-ui
===============================

A utility package for better Optimistic UI support in Laravel Livewire.

1.0.1(1y ago)77MITJavaScriptPHP ^8.2

Since Jun 9Pushed 1y ago1 watchersCompare

[ Source](https://github.com/Capevace/livewire-optimistic-ui)[ Packagist](https://packagist.org/packages/capevace/livewire-optimistic-ui)[ Docs](https://github.com/capevace/livewire-optimistic-ui)[ RSS](/packages/capevace-livewire-optimistic-ui/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (12)Versions (3)Used By (0)

Livewire Optimistic UI – A utility package for better Optimistic UI support in Laravel Livewire.
================================================================================================

[](#livewire-optimistic-ui--a-utility-package-for-better-optimistic-ui-support-in-laravel-livewire)

    Demo.mp4    Installation
------------

[](#installation)

You can install the package via composer:

```
composer require capevace/livewire-optimistic-ui
```

Example
-------

[](#example)

```
# In your Livewire component's .blade.php file

    Add +

    @foreach($todos as $task)

    @endforeach

```

```
use Capevace\OptimisticUI\WithOptimisticUI;
use Capevace\OptimisticUI\Optimistic;

/**
 * @property-read Collection $todos
 */
class OptimisticPage extends Component
{
    use WithOptimisticUI;

    #[Optimistic(crud: 'create', model: Task::class, injectOptimisticId: true)]
    public function addTask(string $id, string $text): void
    {
        if (!uuid_is_valid($id) || Task::find($id)) {
            return;
        }

        $task = new Task([
            'text' => $text,
        ]);

        $task->id = $id;
        $task->save();
    }

    #[Optimistic(crud: 'delete', model: Task::class)]
    public function deleteTask(string $id): void
    {
        Task::find($id)?->delete();
    }

    #[Optimistic(crud: 'update', model: Task::class)]
    public function editTask(string $id, string $text): void
    {
        Task::find($id)?->update([
            'text' => $text,
        ]);
    }

    #[Computed]
    public function todos(): Collection
    {
        return Task::all();
    }

    public function render(): \Illuminate\View\View
    {
        return view("messages", [
            'todos' => $this->todos,
        ]);
    }
}
```

---

Usage
-----

[](#usage)

### Adding optimistic UI to your Livewire component

[](#adding-optimistic-ui-to-your-livewire-component)

You need to wrap your UI with the `x-optimistic::injector` component. This component will handle the optimistic UI for you.

```

```

You can then call your functions optimistically by using the `$optimistic` object.

```

@foreach($todos as $task)

@endforeach
```

### Displaying the added items

[](#displaying-the-added-items)

You can use the `x-optimistic::added` directive to display items that are added optimistically. The component will loop all added items and makes each available in the `$item` variable.

```

```

Optimistic Directives
---------------------

[](#optimistic-directives)

You can add the `x-optimistic` directive to inject the optimistic state of a given item. The ID will be inferred from the `wire:key` attribute or can be passed with `x-optimistic=""`.

```

```

Optimistic Functions
--------------------

[](#optimistic-functions)

To add an optimistic function to your Livewire component, you can use the `#[Optimistic]` attribute.

```
use Capevace\OptimisticUI\Optimistic;

#[Optimistic(
    fn: "update(params[0], { message: params[1] })"
)]
public function changeMessage(string $id, string $message): void
{
    Message::find($id)->update([
        'message' => $message,
    ]);
}
```

The Javascript in the `fn` parameter will be executed on the client-side when the function is called. The `params` array contains the parameters passed to the function.

### Locally generated IDs

[](#locally-generated-ids)

When creating new items, a new UUID will be generated for the item. This ID identifies the item in transit. If you use this ID to actually create the item, you can support interactions with the items in transit, as they will be queued.

To use this feature, set the `injectOptimisticId` parameter to `true`.

Locally, you'd still be calling `$optimized.addTask(text)`, but the ID will be injected server-side.

```
#[Optimistic(
    fn: "create({ text: params[0] })"
    injectOptimisticId: true
)]
public function addTask(string $id, string $text): void
{
    if (!uuid_is_valid($id) || Task::find($id)) {
        return;
    }

    $task = new Task([
        'text' => $text,
    ]);

    $task->id = $id;
    $task->save();
}
```

### Ready-made CRUD functions

[](#ready-made-crud-functions)

The most commonly used functions are implemented out of the box using the `crud` parameter.

Setting this to `create`, `update`, or `delete` will look at your PHP function's parameters using reflection and automatically generate the Javascript function for you.

You also need to supply the `model` parameter, which is then used to only allow updates to `fillable` attributes.

```
#[Optimistic(crud: 'create', model: Task::class)]
public function addTask(string $id, string $text): void
{
    if (!uuid_is_valid($id) || Task::find($id)) {
        return;
    }

    $task = new Task([
        'text' => $text,
    ]);

    $task->id = $id;
    $task->save();
}

#[Optimistic(crud: 'delete', model: Task::class)]
public function deleteTask(string $id): void
{
    Task::find($id)?->delete();
}

#[Optimistic(crud: 'update', model: Task::class)]
public function editTask(string $id, string $text): void
{
    Task::find($id)?->update([
        'text' => $text,
    ]);
}
```

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Lukas Mateffy](https://github.com/Capevace)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

28

—

LowBetter than 54% of packages

Maintenance32

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% 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 ~0 days

Total

2

Last Release

703d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e572442281b0c1b6e8e8f966cc908161a66c4c822e950ff278f8f90dc4f2d2cd?d=identicon)[mateffy](/maintainers/mateffy)

---

Top Contributors

[![Capevace](https://avatars.githubusercontent.com/u/10093858?v=4)](https://github.com/Capevace "Capevace (8 commits)")

---

Tags

laravellivewireLukas Mateffyoptimistic-ui

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/capevace-livewire-optimistic-ui/health.svg)

```
[![Health](https://phpackages.com/badges/capevace-livewire-optimistic-ui/health.svg)](https://phpackages.com/packages/capevace-livewire-optimistic-ui)
```

###  Alternatives

[spatie/laravel-data

Create unified resources and data transfer objects

1.7k28.9M627](/packages/spatie-laravel-data)[hirethunk/verbs

An event sourcing package that feels nice.

513162.9k6](/packages/hirethunk-verbs)[worksome/exchange

Check Exchange Rates for any currency in Laravel.

123544.7k](/packages/worksome-exchange)[ralphjsmit/livewire-urls

Get the previous and current url in Livewire.

82270.3k4](/packages/ralphjsmit-livewire-urls)[hydrat/filament-table-layout-toggle

Filament plugin adding a toggle button to tables, allowing user to switch between Grid and Table layouts.

6292.3k1](/packages/hydrat-filament-table-layout-toggle)[ralphjsmit/laravel-helpers

A package containing handy helpers for your Laravel-application.

13704.6k2](/packages/ralphjsmit-laravel-helpers)

PHPackages © 2026

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