Day 10 - Component Challenge

Challenge UI with Livewire & Alpine.js

Day 10

Day 10

Drawer & Toast

Navigation panels and notification system for modern applications

Toast Notifications

Non-intrusive notifications that appear temporarily and auto-dismiss.

Features

  • Multiple positions (6 options)
  • Auto-dismiss with progress bar
  • 4 types: success, error, warning, info
  • Livewire event integration
  • Manual close button

Toast Types

Alpine.js Trigger

Drawer / Sidebar

Slide-in panels for navigation, settings, or additional content.

Features

  • 4 positions (left, right, top, bottom)
  • Multiple width/height options
  • Escape key to close
  • Click outside to close
  • Header, content, footer slots

Drawer Positions

Event-based Control

Control drawers via Alpine.js events:

Usage Examples

Toast Usage

Toast Component

The <x-ui.toast> component displays temporary notifications. 100% Tailwind CSS + Alpine.js.

Basic Setup

Add the toast container once in your layout:

{{-- In your layout file --}}
<x-ui.toast position="bottom-right" />

Trigger from Livewire

// In your Livewire component
public function save()
{
// ... save logic
 
$this->dispatch('toast', [
'type' => 'success',
'title' => 'Saved!',
'message' => 'Your changes have been saved.',
]);
}

Trigger from Alpine.js

<button @click="$dispatch('toast', {
type: 'info',
title: 'Hello!',
message: 'This is a toast notification.'
})">
Show Toast
</button>

Toast Types

{{-- Success --}}
$dispatch('toast', { type: 'success', message: 'Operation successful!' })
 
{{-- Error --}}
$dispatch('toast', { type: 'error', message: 'Something went wrong.' })
 
{{-- Warning --}}
$dispatch('toast', { type: 'warning', message: 'Please review your input.' })
 
{{-- Info --}}
$dispatch('toast', { type: 'info', message: 'New update available.' })

Positions

{{-- Available positions --}}
<x-ui.toast position="top-left" />
<x-ui.toast position="top-center" />
<x-ui.toast position="top-right" />
<x-ui.toast position="bottom-left" />
<x-ui.toast position="bottom-center" />
<x-ui.toast position="bottom-right" /> {{-- default --}}

Custom Duration

{{-- Container default duration --}}
<x-ui.toast :duration="5000" />
 
{{-- Per-toast duration --}}
$dispatch('toast', {
type: 'info',
message: 'This stays for 10 seconds.',
duration: 10000
})
 
{{-- Persistent (no auto-dismiss) --}}
$dispatch('toast', {
type: 'error',
message: 'Click X to dismiss.',
duration: 0
})

Props Reference

Prop Type Default Description
position string bottom-right Toast position
duration int 4000 Auto-dismiss delay (ms)
maxToasts int 5 Maximum visible toasts

Event Payload

Key Type Description
type string success, error, warning, info
title string Optional title
message string Toast message
duration int Override default duration

Drawer Usage

Drawer Component

The <x-ui.drawer> component creates slide-in panels. 100% Tailwind CSS + Alpine.js.

Basic Usage

<x-ui.drawer>
<x-slot:trigger>
<button>Open Drawer</button>
</x-slot:trigger>
 
<x-slot:header>Drawer Title</x-slot:header>
 
<div class="p-4">
Drawer content here
</div>
 
<x-slot:footer>
<button @click="close()">Close</button>
</x-slot:footer>
</x-ui.drawer>

Positions

{{-- Left (default) --}}
<x-ui.drawer position="left">...</x-ui.drawer>
 
{{-- Right --}}
<x-ui.drawer position="right">...</x-ui.drawer>
 
{{-- Top --}}
<x-ui.drawer position="top">...</x-ui.drawer>
 
{{-- Bottom --}}
<x-ui.drawer position="bottom">...</x-ui.drawer>

Width Options (left/right)

<x-ui.drawer position="left" width="sm">...</x-ui.drawer> {{-- 16rem --}}
<x-ui.drawer position="left" width="md">...</x-ui.drawer> {{-- 20rem (default) --}}
<x-ui.drawer position="left" width="lg">...</x-ui.drawer> {{-- 24rem --}}
<x-ui.drawer position="left" width="xl">...</x-ui.drawer> {{-- 28rem --}}
<x-ui.drawer position="left" width="full">...</x-ui.drawer>

Height Options (top/bottom)

<x-ui.drawer position="bottom" height="sm">...</x-ui.drawer> {{-- 12rem --}}
<x-ui.drawer position="bottom" height="md">...</x-ui.drawer> {{-- 18rem --}}
<x-ui.drawer position="bottom" height="lg">...</x-ui.drawer> {{-- 24rem --}}
<x-ui.drawer position="bottom" height="full">...</x-ui.drawer>

Event-based Control

{{-- Open drawer --}}
<button @click="$dispatch('open-drawer')">Open</button>
 
{{-- Close drawer --}}
<button @click="$dispatch('close-drawer')">Close</button>
 
{{-- Toggle drawer --}}
<button @click="$dispatch('toggle-drawer')">Toggle</button>
 
{{-- Target specific drawer by ID --}}
<x-ui.drawer id="settings-drawer">...</x-ui.drawer>
<button @click="$dispatch('open-drawer', { id: 'settings-drawer' })">
Open Settings
</button>

Navigation Sidebar Example

<x-ui.drawer position="left" width="md">
<x-slot:trigger>
<button class="p-2">
<x-lucide-menu class="size-6" />
</button>
</x-slot:trigger>
 
<x-slot:header>Navigation</x-slot:header>
 
<nav class="p-4 space-y-1">
<a href="#" class="flex items-center gap-3 px-3 py-2 rounded-lg bg-primary/10 text-primary">
<x-lucide-home class="size-5" />
Dashboard
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-accent">
<x-lucide-users class="size-5" />
Users
</a>
<a href="#" class="flex items-center gap-3 px-3 py-2 rounded-lg hover:bg-accent">
<x-lucide-settings class="size-5" />
Settings
</a>
</nav>
 
<x-slot:footer>
<div class="flex items-center gap-3">
<x-ui.avatar name="John Doe" size="sm" />
<span class="text-sm">John Doe</span>
</div>
</x-slot:footer>
</x-ui.drawer>

Disable Close Behaviors

{{-- Keep open on escape key --}}
<x-ui.drawer :close-on-escape="false">...</x-ui.drawer>
 
{{-- Keep open on click outside --}}
<x-ui.drawer :close-on-click-outside="false">...</x-ui.drawer>
 
{{-- No overlay --}}
<x-ui.drawer :overlay="false">...</x-ui.drawer>

Props Reference

Prop Type Default Description
position string left left, right, top, bottom
width string md sm, md, lg, xl, full
height string auto sm, md, lg, full
overlay bool true Show backdrop overlay
closeOnEscape bool true Close on Escape key
closeOnClickOutside bool true Close on overlay click

Slots

Slot Description
trigger Button/element that opens the drawer
header Header content with close button
default Main drawer content
footer Footer content