Snippet 5: Creating a simple, but cool delete button with Alpine.js and TailwindCSS
Sometimes ideas pop into my head that I don't immediately need, but I think are a good exercise. So I carve out 15 minutes of my day to code an example to learn and save to my library of components for future use.
The idea today came from building a delete modal for a website. I just found it to be a lot of code and work to pop up a whole extra element for the sheer use of just clicking a confirm button.
So I figured why not give it a shot and inline it. Keep in mind I've put no thought into any accessibility or mobile aspects of this type of approach.
I wanted it to use Alpine.js, Tailwind, have transitions, support dark mode, and localization.
This is what I came up with:
I even made it dispatch an event so that it can disable other delete buttons around it if need be:
It uses a regular HTML form under the hood with a delete request, so you would need a Laravel route like so:
Route::delete('{item}', [ItemController::class, 'delete'])->name('item.delete')
This is how you would use it:
<x-buttons.delete :action="route('item.delete', $item)" />
Final Component
@props(['action', 'buttonText' => __('Delete')])
<div x-data="{ initial: true, deleting: false }" class="text-sm flex items-center">
<button
x-on:click.prevent="deleting = true; initial = false"
x-show="initial"
x-on:deleting.window="$el.disabled = true"
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0 transform scale-90"
x-transition:enter-end="opacity-100 transform scale-100"
class="text-white p-1 rounded bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 disabled:opacity-50"
>
{{ $buttonText }}
</button>
<div
x-show="deleting"
x-transition:enter="transition ease-out duration-150"
x-transition:enter-start="opacity-0 transform scale-90"
x-transition:enter-end="opacity-100 transform scale-100"
x-transition:leave="transition ease-in duration-150"
x-transition:leave-start="opacity-100 transform scale-100"
x-transition:leave-end="opacity-0 transform scale-90"
class="flex items-center space-x-3"
>
<span class="dark:text-white">@lang('Are you sure?')</span>
<form x-on:submit="$dispatch('deleting')" method="post" action="{{ $action }}">
@csrf
@method('delete')
<button
x-on:click="$el.form.submit()"
x-on:deleting.window="$el.disabled = true"
type="submit"
class="text-white p-1 rounded bg-red-600 hover:bg-red-700 dark:bg-red-500 dark:hover:bg-red-600 disabled:opacity-50"
>
@lang('Yes')
</button>
<button
x-on:click.prevent="deleting = false; setTimeout(() => { initial = true }, 150)"
x-on:deleting.window="$el.disabled = true"
class="text-white p-1 rounded bg-gray-600 hover:bg-gray-700 dark:bg-gray-500 dark:hover:bg-gray-600 disabled:opacity-50"
>
@lang('No')
</button>
</form>
</div>
</div>