# 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 `` element: - **Native `` element**: Uses `showModal()` for true modal behavior - **Automatic backdrop**: Native `::backdrop` pseudo-element - **Automatic focus management**: Browser handles focus trapping - **Automatic ESC handling**: Native `cancel` event - **Z-index management**: Manual stacking for nested modals - **Stack tracking**: Manages multiple open modals #### Native `` Benefits The `` element provides: - **True modal behavior**: Blocks background interaction via `showModal()` - **Native backdrop**: Automatic overlay with `::backdrop` pseudo-element - **Automatic focus trapping**: Browser handles focus management - **Automatic ESC handling**: Native `cancel` event - **Better accessibility**: Native ARIA attributes and semantics - **Better performance**: Native browser implementation - **Wide browser support**: Chrome 37+, Firefox 98+, Safari 15.4+ The system uses native `` features for optimal modal behavior and accessibility. ### Best Practices 1. **Use UIHelper**: Prefer the UIHelper class over manual event dispatching for type safety and convenience 2. **Component IDs**: Always provide component IDs for modals to enable proper management 3. **Toast Duration**: Use appropriate durations (5s for success, longer for errors) 4. **Modal Sizes**: Choose appropriate sizes (small for alerts, large for forms) 5. **Error Handling**: Always show user-friendly error messages ```php // Good: Clear, user-friendly toast (new UIHelper($events))->successToast('Product saved successfully!'); // Bad: Technical error message (new UIHelper($events))->errorToast('SQL Error: INSERT failed'); ``` --- ## Notification Component ### Overview The NotificationComponent is a full-featured LiveComponent for displaying toast notifications with support for different types, positions, durations, and action buttons. **Features**: - Type-safe state management - Multiple notification types (info, success, warning, error) - Configurable positions (top-right, top-left, bottom-right, bottom-left) - Auto-dismiss with duration - Action buttons - Icon support ### Basic Usage ```php use App\Application\LiveComponents\Notification\NotificationComponent; use App\Framework\LiveComponents\ValueObjects\ComponentId; final class ProductController { public function create(): ViewResult { $notification = NotificationComponent::mount( ComponentId::generate('notification'), message: 'Product created successfully', type: 'success', duration: 5000 ); return new ViewResult('product/index', [ 'notification' => $notification ]); } } ``` ### Template Integration ```html {notification}
``` ### Server-Side Actions ```php final class NotificationExample extends LiveComponent { #[Action] public function showSuccess(): NotificationState { return NotificationState::empty() ->withMessage('Operation successful!', 'success') ->show(); } #[Action] public function showError(string $message): NotificationState { return NotificationState::empty() ->withMessage($message, 'error') ->show(); } #[Action] public function showWithAction(): NotificationState { return new NotificationState( message: 'File uploaded successfully', type: 'success', isVisible: true, actionText: 'View', actionUrl: '/files' ); } } ``` ### Client-Side API ```javascript // Show notification via LiveComponent action liveComponentManager.executeAction('notification-id', 'showNotification', { message: 'Operation successful', type: 'success', duration: 5000 }); // Hide notification liveComponentManager.executeAction('notification-id', 'hide'); ``` ### Notification Types ```php // Info notification $notification = NotificationState::empty() ->withMessage('New update available', 'info') ->show(); // Success notification $notification = NotificationState::empty() ->withMessage('Changes saved', 'success') ->show(); // Warning notification $notification = NotificationState::empty() ->withMessage('Low disk space', 'warning') ->show(); // Error notification $notification = NotificationState::empty() ->withMessage('Upload failed', 'error') ->show(); ``` ### Notification Positions ```php $notification = new NotificationState( message: 'Notification message', type: 'info', position: 'top-right', // or 'top-left', 'bottom-right', 'bottom-left' isVisible: true ); ``` ### Notification with Action Button ```php $notification = new NotificationState( message: 'File ready for download', type: 'success', isVisible: true, actionText: 'Download', actionUrl: '/download/file.pdf' ); ``` --- ## Dialog & Modal Integration ### Overview LiveComponents integrate seamlessly with the UIManager for dialogs and modals, providing a consistent API across the application. ### Basic Modal Usage ```php use App\Framework\LiveComponents\Attributes\Action; final class UserSettings extends LiveComponent { #[Action] public function showEditModal(int $userId): void { // Modal will be shown via UI Helper $this->uiHelper->showModal( title: 'Edit User', content: $this->renderEditForm($userId), size: 'large', buttons: [ ['label' => 'Save', 'action' => 'save', 'variant' => 'primary'], ['label' => 'Cancel', 'action' => 'cancel'] ] ); } } ``` ### Modal with LiveComponent Content ```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 showUserModal(int $userId, ?ComponentEventDispatcher $events = null): void { $userComponent = UserDetailsComponent::mount( ComponentId::generate('user-details'), userId: $userId ); (new UIHelper($events))->modal( $this->id, 'User Details', $userComponent->render(), ModalOptions::create()->withSize(ModalSize::Medium) ); } ``` ### Modal Events ```javascript // Listen for modal events window.addEventListener('livecomponent:modal-opened', (e) => { const { componentId, modalInstance } = e.detail; console.log(`Modal opened for component: ${componentId}`); }); window.addEventListener('livecomponent:modal-closed', (e) => { const { componentId, action } = e.detail; console.log(`Modal closed with action: ${action}`); }); ``` --- ## Best Practices ### 1. Tooltip Usage - **Do**: Use tooltips for helpful context and validation errors - **Don't**: Overuse tooltips - they can be distracting - **Accessibility**: Always ensure tooltips are keyboard-accessible ```html ``` ### 2. Loading States - **Do**: Use skeleton loading for content-heavy updates - **Do**: Use spinners for quick actions (< 500ms) - **Don't**: Show loading for optimistic UI updates - **Do**: Configure appropriate delays to prevent flickering ```php // Good: Appropriate loading type #[Loading(type: 'skeleton', fragments: ['product-list'])] public function loadProducts(): void { } // Good: Quick action with spinner #[Loading(type: 'spinner', showDelay: 0)] public function toggleFavorite(): void { } ``` ### 3. Notifications - **Do**: Use notifications for important feedback - **Don't**: Overuse notifications - they can be annoying - **Do**: Set appropriate durations (5s for success, longer for errors) - **Do**: Provide action buttons for actionable notifications ```php // Good: Clear, actionable notification $notification = new NotificationState( message: 'File uploaded successfully', type: 'success', duration: 5000, actionText: 'View', actionUrl: '/files' ); // Bad: Too many notifications // Don't show a notification for every minor action ``` ### 4. Modals & Dialogs - **Do**: Use modals for important confirmations - **Don't**: Overuse modals - they interrupt user flow - **Do**: Provide clear action buttons - **Do**: Support keyboard navigation (Escape to close) ```php // Good: Clear confirmation dialog $this->uiHelper->showConfirm( title: 'Delete Item', message: 'This action cannot be undone.', confirmText: 'Delete', cancelText: 'Cancel' ); ``` ### 5. Error Handling - **Do**: Use ErrorBoundary for automatic error handling - **Do**: Show user-friendly error messages - **Do**: Provide retry options for recoverable errors - **Don't**: Show technical error details to users ```php // Good: User-friendly error throw LiveComponentError::validation( 'Please enter a valid email address', ['field' => 'email'], $this->id->toString() ); // Bad: Technical error throw new \Exception('Invalid email format: ' . $email); ``` --- ## Configuration ### Global Configuration ```javascript import { sharedConfig } from './modules/livecomponent/SharedConfig.js'; // Configure default values sharedConfig.defaultDebounce = 300; sharedConfig.defaultCacheTTL = 5000; sharedConfig.defaultLoadingShowDelay = 150; sharedConfig.defaultLoadingType = 'skeleton'; sharedConfig.defaultNotificationDuration = 5000; sharedConfig.defaultNotificationPosition = 'top-right'; sharedConfig.defaultModalAnimation = 'fade'; ``` ### Per-Component Configuration ```html
``` --- ## Troubleshooting ### Tooltips Not Showing 1. Check that `data-tooltip` attribute is present 2. Verify TooltipManager is initialized 3. Check browser console for errors 4. Ensure element is visible and not hidden ### Loading States Not Working 1. Verify `data-loading-type` attribute is set 2. Check that fragments match between HTML and PHP 3. Ensure LoadingStateManager is initialized 4. Check for JavaScript errors in console ### Notifications Not Displaying 1. Verify NotificationComponent is mounted 2. Check that component ID matches 3. Ensure state is properly serialized 4. Check browser console for errors ### Modals Not Opening 1. Verify UIManager is initialized 2. Check that modal content is valid HTML 3. Ensure no JavaScript errors are blocking execution 4. Check z-index conflicts --- **Next**: [API Reference](api-reference.md) →