Livewire Components
Livewire Components
Overview
UltraViolet Pro includes 9 production-ready Livewire components that demonstrate best practices and real-world functionality. Each component is fully functional, well-documented, and ready to use or customize.
Component Library
1. Counter Component
Location: app/Livewire/Counter.php
View: resources/views/livewire/counter.blade.php
Route: /livewire/components/counter
A simple counter that demonstrates the basics of Livewire.
Features:
- Increment/decrement buttons
- Reset functionality
- Real-time state management
- Clean, minimal design
Usage:
<livewire:counter />
Code Example:
<?php
namespace App\Livewire;
use Livewire\Component;
class Counter extends Component
{
public $count = 0;
public function increment()
{
$this->count++;
}
public function decrement()
{
$this->count--;
}
public function render()
{
return view('livewire.counter');
}
}
2. Mini Counter
Location: app/Livewire/MiniCounter.php
View: resources/views/livewire/mini-counter.blade.php
Route: Embedded in /livewire/dashboard
A compact counter widget perfect for dashboards and sidebars.
Features:
- Compact design
- Multiple increment options (1, 5, 10)
- Reset button
- Card-based layout
Usage:
<livewire:mini-counter />
Perfect For:
- Dashboard widgets
- Sidebar components
- Quick counters in small spaces
3. Todo List
Location: app/Livewire/Todo.php
View: resources/views/livewire/components/todo.blade.php
Route: /livewire/components/todo
Full-featured task management component.
Features:
- Add new tasks
- Mark tasks as complete/incomplete
- Delete tasks
- Task filtering (all, active, completed)
- Empty state handling
- Form validation
Usage:
<livewire:todo />
Key Methods:
public function addTodo() // Add new task
public function toggle($id) // Toggle completion
public function delete($id) // Delete task
Great For:
- Project management
- Personal task lists
- Team collaboration tools
4. Quick Todo
Location: app/Livewire/QuickTodo.php
View: resources/views/livewire/quick-todo.blade.php
Route: Embedded in /livewire/dashboard
Streamlined todo widget for quick task management.
Features:
- Compact interface
- Inline task addition
- One-click toggle
- Delete on hover
- Pre-seeded with examples
Usage:
<livewire:quick-todo />
Differences from Full Todo:
- Simplified UI
- No filtering options
- Designed for dashboard use
- Minimal visual footprint
5. Contact Form
Location: app/Livewire/ContactForm.php
View: resources/views/livewire/components/form.blade.php
Route: /livewire/components/form
Professional contact form with validation.
Features:
- Real-time validation
- Error messages
- Success feedback
- Email input with validation
- Message textarea
- Bootstrap styling
Usage:
<livewire:contact-form />
Validation Rules:
protected $rules = [
'name' => 'required|min:3',
'email' => 'required|email',
'message' => 'required|min:10'
];
Real-Time Validation:
<input wire:model.blur="name">
@error('name') <span class="error">{{ $message }}</span> @enderror
6. Search Component
Location: app/Livewire/Search.php
View: resources/views/livewire/components/search.blade.php
Route: /livewire/components/search
Real-time search with instant results.
Features:
- Live search as you type
- Debounced input (300ms)
- Result highlighting
- Empty state handling
- Sorting options
- Pagination support
Usage:
<livewire:search />
Search Implementation:
public $search = '';
public function render()
{
$results = User::where('name', 'like', "%{$this->search}%")
->orWhere('email', 'like', "%{$this->search}%")
->limit(10)
->get();
return view('livewire.search', ['results' => $results]);
}
Wire Modifiers:
<!-- Live (instant) -->
<input wire:model.live="search">
<!-- Debounced -->
<input wire:model.live.debounce.300ms="search">
<!-- On blur -->
<input wire:model.blur="search">
7. Vector Maps
Location: app/Livewire/MapsVector.php
View: resources/views/livewire/maps-vector.blade.php
Route: /livewire/components/vector-maps
Interactive map component with controls.
Features:
- Multiple map styles (street, satellite, terrain)
- Layer toggles (traffic, buildings, POI)
- Zoom controls
- Reset view button
- Livewire state management
- JSVectorMap integration
Usage:
<livewire:maps-vector />
Map Controls:
public function changeMapStyle($style) // Switch map style
public function toggleTrafficLayer() // Show/hide traffic
public function toggleBuildingsLayer() // Show/hide buildings
public function zoomIn() // Zoom in
public function zoomOut() // Zoom out
public function resetView() // Reset to default
JavaScript Integration:
@push('scripts')
<script>
Livewire.on('mapUpdated', (data) => {
// Update map based on Livewire state
map.setStyle(data.style);
});
</script>
@endpush
8. Chirps (Social Media)
Location: app/Livewire/Chirps.php
View: resources/views/livewire/chirps.blade.php
Route: /chirper
Full social media posting component (like Twitter/X).
Features:
- Create new chirps
- Edit own chirps
- Delete own chirps
- Character counter
- Timestamp display
- User authentication
- Policy-based authorization
- Real-time updates
- Demo data integration
Data Requirements:
- Requires
chirpstable (created by migration) - Uses
DemoChirpServicefor sample data - Mixes real database chirps with demo chirps
- User authentication required for posting
Usage:
<livewire:chirps />
Key Features:
public function store() // Create chirp
public function edit($id) // Edit mode
public function update() // Save changes
public function delete($id) // Delete chirp
Authorization:
// In ChirpPolicy.php
public function update(User $user, Chirp $chirp)
{
return $chirp->user()->is($user);
}
Character Limit:
<textarea
wire:model="message"
maxlength="255"
></textarea>
<span>{{ strlen($message) }}/255</span>
9. Stats Widget
Location: app/Livewire/StatsWidget.php
View: resources/views/livewire/stats-widget.blade.php
Route: Embedded in /livewire/dashboard
Live statistics widget with auto-refresh.
Features:
- Real-time stat updates
- Auto-refresh (every 5 seconds)
- Multiple metrics (visitors, sales, revenue)
- Animated counters
- Responsive cards
Usage:
<livewire:stats-widget />
Auto-Refresh:
#[On('refresh-stats')]
public function refreshStats()
{
$this->visitors = rand(100, 500);
$this->sales = rand(10, 50);
$this->revenue = rand(1000, 5000);
}
Polling:
<div wire:poll.5s="refreshStats">
<!-- Stats display -->
</div>
Component Data Requirements
Database Setup Required
Some components require database setup to function properly:
1. Chirps Component
# Run migrations to create chirps table
php artisan migrate
# Seed with sample chirps
php artisan db:seed --class=ChirpSeeder
2. Authentication Components
# Run migrations for users table
php artisan migrate
# Seed with test users
php artisan db:seed --class=UserSeeder
3. All Components Demo Data
# Seed all demo data at once
php artisan db:seed
Component Dependencies
| Component | Database Required | Seeder Required | Auth Required |
|---|---|---|---|
| Counter | ❌ | ❌ | ❌ |
| Mini Counter | ❌ | ❌ | ❌ |
| Todo List | ❌ | ❌ | ❌ |
| Quick Todo | ❌ | ❌ | ❌ |
| Contact Form | ❌ | ❌ | ❌ |
| Search | ✅ Users table | UserSeeder | ❌ |
| Vector Maps | ❌ | ❌ | ❌ |
| Chirps | ✅ Chirps table | ChirpSeeder | ✅ |
| Stats Widget | ❌ | ❌ | ❌ |
Quick Setup for All Components
# Complete setup for all components
php artisan migrate:fresh --seed
# This will:
# 1. Drop all tables
# 2. Re-run all migrations
# 3. Seed with all demo data
# 4. Create test users
# 5. Create sample chirps
Common Patterns
Wire Directives
wire:model - Two-way data binding
<input wire:model="name">
wire:click - Click events
<button wire:click="save">Save</button>
wire:submit - Form submission
<form wire:submit="submit">
wire:loading - Loading states
<span wire:loading>Saving...</span>
wire:poll - Polling/auto-refresh
<div wire:poll.5s="refresh">
Modifiers
live - Real-time updates
<input wire:model.live="search">
debounce - Delay updates
<input wire:model.live.debounce.500ms="search">
blur - Update on blur
<input wire:model.blur="email">
prevent - Prevent default
<form wire:submit.prevent="save">
Component Communication
Events
Dispatch events:
$this->dispatch('userSaved', userId: $user->id);
Listen for events:
#[On('userSaved')]
public function handleUserSaved($userId)
{
// Handle event
}
JavaScript listeners:
@push('scripts')
<script>
Livewire.on('userSaved', (data) => {
console.log('User saved:', data.userId);
});
</script>
@endpush
Validation
Real-Time Validation
class ContactForm extends Component
{
public $email;
protected $rules = [
'email' => 'required|email'
];
public function updated($propertyName)
{
$this->validateOnly($propertyName);
}
}
Display Errors
<input wire:model="email">
@error('email')
<span class="text-danger">{{ $message }}</span>
@enderror
File Uploads
use Livewire\WithFileUploads;
class FileUpload extends Component
{
use WithFileUploads;
public $photo;
public function save()
{
$this->validate([
'photo' => 'image|max:1024'
]);
$this->photo->store('photos');
}
}
<input type="file" wire:model="photo">
@if ($photo)
<img src="{{ $photo->temporaryUrl() }}">
@endif
<button wire:click="save">Upload</button>
Pagination
use Livewire\WithPagination;
class Users extends Component
{
use WithPagination;
public function render()
{
return view('livewire.users', [
'users' => User::paginate(10)
]);
}
}
@foreach($users as $user)
<div>{{ $user->name }}</div>
@endforeach
{{ $users->links() }}
Performance Tips
1. Use Wire:loading for Feedback
<button wire:click="save">
<span wire:loading.remove>Save</span>
<span wire:loading>Saving...</span>
</button>
2. Debounce Search Inputs
<input wire:model.live.debounce.500ms="search">
3. Use wire:key for Lists
@foreach($items as $item)
<div wire:key="item-{{ $item->id }}">
{{ $item->name }}
</div>
@endforeach
4. Lazy Loading
<livewire:stats-widget lazy />
5. Optimize Queries
// Bad
public function render()
{
return view('livewire.users', [
'users' => User::all() // Loads all users!
]);
}
// Good
public function render()
{
return view('livewire.users', [
'users' => User::limit(10)->get()
]);
}
Testing
Feature Test Example
use Livewire\Livewire;
test('can increment counter', function () {
Livewire::test(Counter::class)
->assertSet('count', 0)
->call('increment')
->assertSet('count', 1);
});
Form Test Example
test('validates contact form', function () {
Livewire::test(ContactForm::class)
->set('email', 'invalid-email')
->call('submit')
->assertHasErrors('email');
});
Next Steps
- [Layout System]({{ route('docs.show', 'livewire/layout') }}) - Learn about the Livewire layout
- [Best Practices]({{ route('docs.show', 'livewire/best-practices') }}) - Tips and patterns
- Livewire Docs - Official documentation
Ready to customize? All component source code is fully editable in app/Livewire/ and resources/views/livewire/. Make them your own! 🎨