# LiveComponents UI Integration Guide
**Complete Guide to UI Features: Tooltips, Loading States, Dialogs, and Notifications**
This guide covers the integrated UI features available in LiveComponents, including tooltips, skeleton loading, dialogs, modals, notifications, and loading states.
---
## Table of Contents
1. [Tooltip System](#tooltip-system)
2. [Loading States & Skeleton Loading](#loading-states--skeleton-loading)
3. [UI Helper System](#ui-helper-system)
4. [Event-Based UI Integration](#event-based-ui-integration)
5. [Notification Component](#notification-component)
6. [Dialog & Modal Integration](#dialog--modal-integration)
7. [Best Practices](#best-practices)
---
## Tooltip System
### Overview
The Tooltip System provides automatic tooltip initialization and management for LiveComponent elements. Tooltips are automatically initialized when components are mounted and cleaned up when components are destroyed.
**Features**:
- Automatic initialization for `data-tooltip` attributes
- Accessibility support (ARIA attributes)
- Smart positioning (viewport-aware)
- Validation error tooltips
- Automatic cleanup
### Basic Usage
```html
```
### Server-Side Validation Tooltips
```php
use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\ValueObjects\LiveComponentError;
final class UserForm extends LiveComponent
{
#[Action]
public function validateEmail(string $email): void
{
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
// Error will automatically show tooltip if element has data-tooltip-error
throw LiveComponentError::validation(
'Invalid email format',
['field' => 'email'],
$this->id->toString(),
'validateEmail'
);
}
}
}
```
### Custom Tooltip Configuration
```javascript
// Configure tooltip behavior globally
import { tooltipManager } from './modules/livecomponent/TooltipManager.js';
// Adjust delays
tooltipManager.tooltipDelay = 500; // Show after 500ms
tooltipManager.hideDelay = 200; // Hide after 200ms
```
### Tooltip Events
```javascript
// Listen for tooltip events
window.addEventListener('livecomponent:tooltip-shown', (e) => {
const { element, tooltipText } = e.detail;
console.log(`Tooltip shown: ${tooltipText}`);
});
window.addEventListener('livecomponent:tooltip-hidden', (e) => {
const { element } = e.detail;
console.log('Tooltip hidden');
});
```
---
## Loading States & Skeleton Loading
### Overview
The Loading State System provides configurable loading indicators during LiveComponent actions, including skeleton loaders, spinners, and progress indicators.
**Features**:
- Fragment-specific loading
- Configurable loading types (skeleton, spinner, progress, none)
- Smooth transitions
- Optimistic UI integration (no loading for optimistic actions)
- Per-component configuration
### Basic Usage
```html
```
### Server-Side Loading Configuration
```php
use App\Framework\LiveComponents\Attributes\Action;
use App\Framework\LiveComponents\Attributes\Loading;
final class ProductList extends LiveComponent
{
#[Action]
#[Loading(type: 'skeleton', fragments: ['product-list'], showDelay: 150)]
public function loadProducts(string $category): void
{
$this->products = $this->productService->getByCategory($category);
}
#[Action]
#[Loading(type: 'spinner', showDelay: 0)] // Show immediately
public function quickAction(): void
{
// Fast action with immediate spinner
}
}
```
### Loading Types
#### 1. Skeleton Loading
```html
{product.name}
```
#### 2. Spinner Loading
```html
```
#### 3. Progress Loading
```html
```
### Custom Loading Configuration
```javascript
// Configure loading behavior per component
const component = LiveComponentManager.getInstance().getComponent('component-id');
component.setLoadingConfig({
type: 'skeleton',
fragments: ['content', 'sidebar'],
showDelay: 150,
hideDelay: 100
});
```
### Loading Events
```javascript
// Listen for loading state changes
window.addEventListener('livecomponent:loading-started', (e) => {
const { componentId, type, fragments } = e.detail;
console.log(`Loading started: ${componentId} (${type})`);
});
window.addEventListener('livecomponent:loading-finished', (e) => {
const { componentId, duration } = e.detail;
console.log(`Loading finished: ${componentId} (${duration}ms)`);
});
```
---
## UI Helper System
### Overview
The UI Helper System provides a standardized way for LiveComponents to interact with common UI elements like dialogs, modals, and notifications.
**Features**:
- Unified API for UI components
- Integration with UIManager
- Promise-based API
- Automatic cleanup
- Component-scoped UI elements
### Dialog & Modal Helpers
```php
use App\Framework\LiveComponents\Attributes\Action;
final class UserManagement extends LiveComponent
{
#[Action]
public function showDeleteConfirm(int $userId): void
{
// Show confirmation dialog via UI Helper
$this->uiHelper->showDialog(
title: 'Delete User',
message: 'Are you sure you want to delete this user?',
buttons: [
['label' => 'Cancel', 'action' => 'cancel'],
['label' => 'Delete', 'action' => 'confirm', 'variant' => 'danger']
]
)->then(function($action) use ($userId) {
if ($action === 'confirm') {
$this->deleteUser($userId);
}
});
}
}
```
### JavaScript API
```javascript
import { LiveComponentUIHelper } from './modules/livecomponent/LiveComponentUIHelper.js';
const uiHelper = new LiveComponentUIHelper(liveComponentManager);
// Show modal
const action = await uiHelper.showModal('component-id', {
title: 'Confirm Action',
content: 'Are you sure?
',
size: 'medium',
buttons: [
{ label: 'Cancel', action: 'cancel' },
{ label: 'Confirm', action: 'confirm', variant: 'primary' }
]
});
if (action === 'confirm') {
// Handle confirmation
}
// Show alert
await uiHelper.showAlert('component-id', {
title: 'Success',
message: 'Operation completed successfully',
type: 'success'
});
// Show confirm dialog
const confirmed = await uiHelper.showConfirm('component-id', {
title: 'Delete Item',
message: 'This action cannot be undone.',
confirmText: 'Delete',
cancelText: 'Cancel'
});
```
### Notification Helpers
```javascript
// Show notification
uiHelper.showNotification('component-id', 'Operation successful', 'success');
// Show error notification with retry
uiHelper.showErrorNotification(
'component-id',
'Upload failed. Please try again.',
'error',
true, // Can retry
() => {
// Retry logic
retryUpload();
}
);
// Hide notification
uiHelper.hideNotification('component-id');
```
---
## Event-Based UI Integration
### Overview
The Event-Based UI Integration system allows LiveComponents to trigger UI components (Toasts, Modals) by dispatching events from PHP actions. The JavaScript `UIEventHandler` automatically listens to these events and displays the appropriate UI components.
**Features**:
- Automatic UI component display from PHP events
- Type-safe event payloads
- Toast queue management
- Modal stack management
- Zero JavaScript code required in components
### Architecture
- **PHP Side**: Components dispatch events via `ComponentEventDispatcher`
- **JavaScript Side**: `UIEventHandler` listens to events and displays UI components
- **Integration**: Events are automatically dispatched after action execution
### Basic Usage with UIHelper
The `UIHelper` class provides convenient methods for dispatching UI events:
```php
successToast('Product saved successfully!');
return $this->state->withSaved();
}
#[Action]
public function delete(int $productId, ?ComponentEventDispatcher $events = null): ProductFormState
{
// Show confirmation dialog with action
(new UIHelper($events))->confirmDelete(
$this->id,
"product #{$productId}",
'doDelete',
['id' => $productId]
);
return $this->state;
}
#[Action]
public function doDelete(int $id): ProductFormState
{
// This action is automatically called when user confirms
// ... delete logic ...
return $this->state->withoutProduct($id);
}
}
```
### Toast Events
#### Show Toast
```php
use App\Framework\LiveComponents\UI\UIHelper;
#[Action]
public function save(?ComponentEventDispatcher $events = null): State
{
// Basic success toast
(new UIHelper($events))->successToast('Saved successfully!');
// Toast with custom duration
(new UIHelper($events))->infoToast('File uploaded', 7000);
// Using fluent interface for multiple toasts
(new UIHelper($events))
->infoToast('Processing...')
->successToast('Done!');
return $this->state;
}
```
**Toast Types**:
- `info` - Blue, informational message
- `success` - Green, success message
- `warning` - Orange, warning message
- `error` - Red, error message
**Positions**:
- `top-right` (default)
- `top-left`
- `bottom-right`
- `bottom-left`
#### Hide Toast
```php
#[Action]
public function dismissNotification(?ComponentEventDispatcher $events = null): State
{
$this->hideToast($events, 'global');
return $this->state;
}
```
### Modal Events
#### Show Modal
```php
use App\Framework\LiveComponents\UI\UIHelper;
use App\Framework\LiveComponents\Events\UI\Options\ModalOptions;
use App\Framework\LiveComponents\Events\UI\Enums\ModalSize;
#[Action]
public function showEditForm(int $userId, ?ComponentEventDispatcher $events = null): State
{
$formHtml = $this->renderEditForm($userId);
(new UIHelper($events))->modal(
$this->id,
'Edit User',
$formHtml,
ModalOptions::create()
->withSize(ModalSize::Large)
->withButtons([
['text' => 'Save', 'class' => 'btn-primary', 'action' => 'save'],
['text' => 'Cancel', 'class' => 'btn-secondary', 'action' => 'close']
])
);
return $this->state;
}
```
#### Show Confirmation Dialog
```php
use App\Framework\LiveComponents\UI\UIHelper;
#[Action]
public function requestDelete(int $id, ?ComponentEventDispatcher $events = null): State
{
(new UIHelper($events))->confirmDelete(
$this->id,
"item #{$id}",
'doDelete',
['id' => $id]
);
return $this->state;
}
```
**Note**: Confirmation dialogs return a result via the `modal:confirm:result` event. You can listen to this event in JavaScript to handle the confirmation:
```javascript
document.addEventListener('modal:confirm:result', (e) => {
const { componentId, confirmed } = e.detail;
if (confirmed) {
// User confirmed - execute action
LiveComponentManager.getInstance()
.executeAction(componentId, 'confirmDelete', { id: 123 });
}
});
```
#### Show Alert Dialog
```php
use App\Framework\LiveComponents\UI\UIHelper;
#[Action]
public function showError(?ComponentEventDispatcher $events = null): State
{
(new UIHelper($events))->alertError(
$this->id,
'Error',
'An error occurred while processing your request.'
);
return $this->state;
}
```
#### Close Modal
```php
use App\Framework\LiveComponents\UI\UIHelper;
#[Action]
public function closeModal(?ComponentEventDispatcher $events = null): State
{
(new UIHelper($events))->closeModal($this->id);
return $this->state;
}
```
### Manual Event Dispatching
If you prefer to dispatch events manually (without UIHelper):
```php
use App\Framework\LiveComponents\ComponentEventDispatcher;
use App\Framework\LiveComponents\Events\UI\ToastShowEvent;
#[Action]
public function save(?ComponentEventDispatcher $events = null): State
{
// ... save logic ...
if ($events !== null) {
// Option 1: Using Event classes (recommended)
$events->dispatchEvent(ToastShowEvent::success('Saved successfully!'));
// Option 2: Direct instantiation
$events->dispatchEvent(new ToastShowEvent(
message: 'Saved successfully!',
type: 'success',
duration: 5000
));
}
return $this->state;
}
```
### JavaScript Event Handling
The `UIEventHandler` automatically listens to these events and displays UI components. You can also listen to events manually:
```javascript
// Listen to toast events
document.addEventListener('toast:show', (e) => {
const { message, type, duration, position } = e.detail;
console.log(`Toast: ${message} (${type})`);
});
// Listen to modal events
document.addEventListener('modal:show', (e) => {
const { componentId, title, content } = e.detail;
console.log(`Modal shown: ${title}`);
});
// Listen to confirmation results
document.addEventListener('modal:confirm:result', (e) => {
const { componentId, confirmed } = e.detail;
if (confirmed) {
// Handle confirmation
}
});
```
### Toast Queue Management
The `ToastQueue` automatically manages multiple toasts:
- Maximum 5 toasts per position (configurable)
- Automatic stacking with spacing
- Oldest toast removed when limit reached
- Auto-dismiss with queue management
### Modal Stack Management
The `ModalManager` handles modal stacking using native `