custom toggle action

I'm trying to learn filament and how to extend the features. Ihave a table header where I want 3 toggle actions, and they're neither form actions or table actions, or toggle column, so I figured i needed to create a cutom action to extend the action... I have it sort of working but it's very ugly and it doesn't interact with sme of the features like requiresConfirmation. Has anyone managed to make a custom toggle action I could learn from their code? Or suggested reading?
5 Replies
_andypeacock
_andypeacock6mo ago
Hi @justlasse Did you ever find a good solution to this? I'm looking for a toggle in the headerActions section as well.
awcodes
awcodes6mo ago
What have you tried?. You would definitely need a custom action with a custom view since there isn’t a toggle action type.
_andypeacock
_andypeacock6mo ago
I've never gotten my head round how to get livewire working properly for passing properties. I've been busy spamming ChatGPT and Clause, and still can't get it working 😦 I think I'm going to give up and try again tomorrow.
awcodes
awcodes6mo ago
It’s ok to walk away when you get stuck. I’ve had to walk away from Tiptap for days at a time before.
_andypeacock
_andypeacock6mo ago
Almost got it sorted. The livewire component is rendered via the action view() which renders a view consisting of only the livewire component (that seems inefficient, but it's the only way I know to render livewire in the view). The UI toggles, and it's internal state changes. Just need to work out how to get that state back into the action. I'll share code later today when I'm back at my pc And got it sorted. Except the initial state isn't working quite right. Will post code here later. OK, initial state sorted: In header actions:
Action::make('toggle')
->action(function () {
// This action will be handled by the Livewire component
logger("filament toggle");
})
->view('filament.components.toggle', [
'label' => "Show completed?"
]),
Action::make('toggle')
->action(function () {
// This action will be handled by the Livewire component
logger("filament toggle");
})
->view('filament.components.toggle', [
'label' => "Show completed?"
]),
resources/views/filament/components/toggle.blade.php
<div class="grid grid-cols-1 grid-rows-2 justify-items-center">
<div>
<livewire:toggle-button name="show-completed" :initial-state="true" />
</div>
<div>{{ $label }}</div>
</div>
<div class="grid grid-cols-1 grid-rows-2 justify-items-center">
<div>
<livewire:toggle-button name="show-completed" :initial-state="true" />
</div>
<div>{{ $label }}</div>
</div>
app/Livewire/ToggleButton.php
<?php

namespace App\Livewire;

use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;

class ToggleButton extends Component implements HasForms, HasActions
{
use InteractsWithActions;
use InteractsWithForms;

public bool $isActive = false;
public $name;
public $label = "";

public function mount($name, $initialState = false)
{
$this->name = $name;
$this->isActive = $initialState;
}

public function toggleAction() : Action
{
return Action::make('toggle')
->action(function (array $arguments) {
$this->isActive = ! $this->isActive;
$this->dispatch('toggleChanged', $arguments, $this->isActive);
})
->view('filament.components.toggle');
}

public function render()
{
return view('livewire.toggle-button');
}
}
<?php

namespace App\Livewire;

use Filament\Actions\Action;
use Filament\Actions\Concerns\InteractsWithActions;
use Filament\Actions\Contracts\HasActions;
use Filament\Forms\Concerns\InteractsWithForms;
use Filament\Forms\Contracts\HasForms;
use Livewire\Component;

class ToggleButton extends Component implements HasForms, HasActions
{
use InteractsWithActions;
use InteractsWithForms;

public bool $isActive = false;
public $name;
public $label = "";

public function mount($name, $initialState = false)
{
$this->name = $name;
$this->isActive = $initialState;
}

public function toggleAction() : Action
{
return Action::make('toggle')
->action(function (array $arguments) {
$this->isActive = ! $this->isActive;
$this->dispatch('toggleChanged', $arguments, $this->isActive);
})
->view('filament.components.toggle');
}

public function render()
{
return view('livewire.toggle-button');
}
}
resources/views/livewire/toggle-button.blade.php
<button wire:click="mountAction('toggle', { name: 'showCompleted' })"
class="{{ $isActive ? 'bg-green-500' : 'bg-gray-300' }} relative w-14 h-8 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-500">
<span class="sr-only" x-text="$wire.entangle('isActive') ? 'On' : 'Off'"></span>
<span
class="{{ $isActive ? 'translate-x-6' : 'translate-x-0' }} absolute left-1 top-1 w-6 h-6 rounded-full bg-white shadow transform transition-transform duration-300 ease-in-out"></span>
</button>
<button wire:click="mountAction('toggle', { name: 'showCompleted' })"
class="{{ $isActive ? 'bg-green-500' : 'bg-gray-300' }} relative w-14 h-8 rounded-full focus:outline-none focus:ring-2 focus:ring-blue-500">
<span class="sr-only" x-text="$wire.entangle('isActive') ? 'On' : 'Off'"></span>
<span
class="{{ $isActive ? 'translate-x-6' : 'translate-x-0' }} absolute left-1 top-1 w-6 h-6 rounded-full bg-white shadow transform transition-transform duration-300 ease-in-out"></span>
</button>
I'm still convinced there are some efficiencies that could be done there, but that works Hope that helps!

Did you find this page helpful?