Holidays Deal Full Access for 50% OFF. Use code LEX50 at checkout

You'll get every theme available plus future additions. That's 45 themes total. Unlimited projects. Lifetime updates. One payment.

How to create an update notification toast with Alpine.js and Tailwind CSS

Learn how to build an interactive update notification toast using Alpine.js for state management and Tailwind CSS for styling, perfect for app updates.

Published on October 13, 2025 by Michael Andreuzza

Update notifications are essential for keeping users informed about new versions and improvements. This tutorial shows how to build a sleek, interactive toast notification that displays update details, allows users to reload or dismiss, and includes expandable notes for more information.

What we’ll build

We’ll create a toast that:

  • Shows update version and notes
  • Includes reload and “later” buttons
  • Features expandable notes section
  • Uses smooth animations
  • Can be triggered programmatically or via demo button
  • Supports custom version and notes

Prerequisites

Make sure Alpine.js and Tailwind CSS are installed in your project. If you’re using Astro, you can include this component directly in any page or layout.

How it works

The toast uses Alpine.js to manage its state and interactions. The x-data object contains:

  • toast: An object with open, version, notes, and expanded properties
  • show(detail): Updates the toast with new data and shows it
  • reload(): Reloads the page
  • later(): Dismisses the toast

The component listens for a custom notify event to trigger updates programmatically.

Triggering the toast

Via Button Click

Click the demo button to simulate an update:

<button
  @click="show({ version:'3.0.0', notes:'Fresh look and faster previews.' })"
>
  Click to simulate update
</button>

Programmatically

Dispatch a custom event from anywhere in your app:

window.dispatchEvent(
  new CustomEvent("notify", {
    detail: { version: "3.0.0", notes: "Fresh look and faster previews." },
  })
);

Customizing the toast

You can customize the version and notes when triggering:

show({
  version: "4.1.2",
  notes: "Bug fixes and new features added.",
});

The toast includes:

  • Smooth slide-in/slide-out animations
  • Expandable notes section for detailed information
  • Accessible design with proper ARIA attributes
  • Responsive layout that works on all screen sizes

This component provides a professional way to notify users about app updates while giving them control over when to apply them.

Full code

Here’s the complete component code:

<div
  class="w-full max-w-xl mx-auto"
  x-data="{
      toast: { open:false, version:'2.3.1', notes:'Performance improvements and small UI fixes.', expanded:false },
      show(detail={}){
        this.toast.version = detail.version || this.toast.version;
        this.toast.notes = detail.notes || this.toast.notes;
        this.toast.expanded = false;
        this.toast.open = true;
      },
      reload(){ try{ location.reload(); }catch{ this.toast.open=false; } },
      later(){ this.toast.open=false; }
    }"
  x-init="window.addEventListener('notify', (e)=> show(e.detail||{}))"
>
  <!-- Demo trigger -->
  <div class="flex items-center justify-center gap-2">
    <button
      class="relative flex items-center justify-center text-center font-medium transition-colors duration-200 ease-in-out select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:z-10 justify-center rounded-md text-zinc-600 bg-zinc-50 outline outline-zinc-100 hover:bg-zinc-200 focus-visible:outline-zinc-600 h-9 px-4 text-sm"
      @click="show({ version:'3.0.0', notes:'Fresh look and faster previews.' })"
    >
      Click to simulate update
    </button>
  </div>
  <!-- Live region (bottom-center) -->
  <div
    aria-live="polite"
    class="fixed inset-x-0 bottom-0 flex justify-center px-4 pb-6 pointer-events-none sm:px-6"
  >
    <div class="flex justify-center w-full max-w-lg">
      <div
        x-show="toast.open"
        x-transition:enter="transform ease-out duration-300"
        x-transition:enter-start="translate-y-2 opacity-0"
        x-transition:enter-end="translate-y-0 opacity-100"
        x-transition:leave="transition ease-in duration-150"
        x-transition:leave-start="opacity-100"
        x-transition:leave-end="opacity-0"
        class="w-full bg-white shadow-lg pointer-events-auto rounded-xl outline outline-1 outline-black/5 transition"
        role="status"
      >
        <div class="p-4">
          <div class="flex items-start gap-3">
            <div class="text-blue-600 shrink-0">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                stroke-width="2"
                stroke-linecap="round"
                stroke-linejoin="round"
                class="icon icon-tabler-arrow-refresh size-5"
              >
                <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                <path d="M20 11a8.1 8.1 0 0 0 -15.5 -2m-.5 -4v4h4"></path>
                <path d="M4 13a8.1 8.1 0 0 0 15.5 2m.5 4v-4h-4"></path>
              </svg>
            </div>
            <div class="flex-1 min-w-0">
              <div class="flex items-center gap-2">
                <p class="text-sm text-sm font-medium text-zinc-900">
                  Update available
                </p>
                <span
                  class="text-[0.70rem] px-2 py-0.5 rounded-full bg-blue-50 text-blue-700"
                  >v<span x-text="toast.version"></span
                ></span>
              </div>
              <p
                class="mt-1 text-xs text-zinc-600 line-clamp-2"
                x-text="toast.notes"
              ></p>
              <div class="flex items-center mt-4 gap-2">
                <button
                  class="relative flex items-center justify-center text-center font-medium transition-colors duration-200 ease-in-out select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:z-10 justify-center rounded-md text-white bg-zinc-900 outline outline-zinc-900 hover:bg-zinc-950 focus-visible:outline-zinc-950 h-7 px-3 text-xs"
                  type="button"
                  @click="reload()"
                >
                  Reload now
                </button>
                <button
                  class="relative flex items-center justify-center text-center font-medium transition-colors duration-200 ease-in-out select-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:z-10 justify-center rounded-md text-zinc-700 bg-white outline outline-zinc-200 hover:shadow-sm hover:bg-zinc-50 focus-visible:outline-zinc-900 h-7 px-3 text-xs"
                  type="button"
                  @click="later()"
                >
                  Later
                </button>
                <button
                  type="button"
                  class="ml-auto font-medium text-xs text-zinc-900 duration-300 hover:underline hover:text-zinc-700"
                  @click="toast.expanded=!toast.expanded"
                  x-text="toast.expanded ? 'Hide notes' : 'View notes'"
                ></button>
              </div>
              <div
                x-show="toast.expanded"
                x-transition.opacity
                class="mt-2 text-[0.70rem] text-zinc-600 bg-zinc-50 rounded-md p-2"
              >
                <pre
                  class="break-words whitespace-pre-wrap font-mono"
                  x-text="toast.notes"
                ></pre>
              </div>
            </div>
            <div class="flex ml-2 shrink-0">
              <button
                class="flex items-center justify-center text-center shadow-subtle font-medium duration-500 ease-in-out transition-colors focus:outline-2 focus:outline-offset-2 text-zinc-600 bg-zinc-50 outline outline-zinc-50 hover:bg-zinc-200 focus:outline-zinc-600 size-7 p-0.5 text-xs rounded-md"
                type="button"
                @click="later()"
              >
                <span class="sr-only">Close</span>
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  viewBox="0 0 24 24"
                  fill="none"
                  stroke="currentColor"
                  stroke-width="2"
                  stroke-linecap="round"
                  stroke-linejoin="round"
                  class="icon icon-tabler-wave-x size-5"
                >
                  <path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
                  <path d="M18 6l-12 12"></path>
                  <path d="M6 6l12 12"></path>
                </svg>
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
```</content>
<parameter name="filePath">/Users/michelandreuzza/Desktop/projects/lexingtonthemes.com/src/content/posts/how-to-create-an-update-notification-toast-with-alpine-js-and-tailwind-css.md

/Michael Andreuzza