Introducing Laravel Quizzes! Play now

This post is more than a year old. There is a chance the content is outdated.

Snippet 5: Creating a simple, but cool delete button with Alpine.js and TailwindCSS

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>
Anthony Rappa

By Anthony Rappa

Hello! I'm a full stack developer from Long Island, New York. Working mainly with Laravel, Tailwind, Livewire, and Alpine.js (TALL Stack). I share everything I know about these tools and more, as well as any useful resources I find from the community. You can find me on GitHub and LinkedIn.