# LiveComponents API Reference
**Complete API Documentation for LiveComponents System**
This reference covers all public classes, methods, attributes, and interfaces for building LiveComponents applications.
---
## Table of Contents
1. [LiveComponent Base Class](#livecomponent-base-class)
2. [Attributes](#attributes)
3. [HTTP Integration](#http-integration)
4. [JavaScript API](#javascript-api)
5. [Value Objects](#value-objects)
6. [Services](#services)
7. [Events](#events)
---
## LiveComponent Base Class
### `abstract class LiveComponent`
Base class for all LiveComponents. Provides lifecycle hooks, rendering, and state management.
#### Properties
```php
/**
* Unique component instance ID
* Auto-generated on component creation
*/
protected readonly string $id;
/**
* Component name (class name without namespace)
*/
protected readonly string $name;
```
#### Lifecycle Methods
##### `public function mount(array $initialData = []): void`
Called when component is first created.
**Parameters**:
- `$initialData` - Initial data passed to component
**Usage**:
```php
public function mount(array $initialData = []): void
{
$this->userId = $initialData['user_id'] ?? null;
$this->loadUserData();
$this->enableSse(); // Enable real-time updates
}
```
---
##### `public function hydrate(array $state): void`
Called on subsequent requests to restore component state.
**Parameters**:
- `$state` - Serialized component state from client
**Usage**:
```php
public function hydrate(array $state): void
{
// State automatically restored to #[LiveProp] properties
// Override for custom hydration logic
parent::hydrate($state);
$this->recalculateDerivedState();
}
```
---
##### `public function updated(string $property, mixed $oldValue, mixed $newValue): void`
Called when a property is updated via two-way binding.
**Parameters**:
- `$property` - Property name that changed
- `$oldValue` - Previous value
- `$newValue` - New value
**Usage**:
```php
public function updated(string $property, mixed $oldValue, mixed $newValue): void
{
if ($property === 'searchTerm' && strlen($newValue) >= 3) {
$this->performSearch();
}
}
```
---
##### `public function unmount(): void`
Called when component is destroyed.
**Usage**:
```php
public function unmount(): void
{
// Clean up resources
$this->closeConnections();
$this->clearCache();
}
```
---
#### Rendering
##### `abstract public function render(): string`
Render component to HTML.
**Returns**: HTML string
**Usage**:
```php
public function render(): string
{
return $this->view('components/user-profile', [
'user' => $this->user,
'posts' => $this->posts
]);
}
```
---
##### `protected function view(string $template, array $data = []): string`
Render a template with data.
**Parameters**:
- `$template` - Template path (relative to views directory)
- `$data` - Data to pass to template
**Returns**: Rendered HTML
**Usage**:
```php
protected function render(): string
{
return $this->view('components/product-list', [
'products' => $this->products,
'totalCount' => $this->totalCount
]);
}
```
---
#### State Management
##### `protected function getState(): array`
Get component state for serialization.
**Returns**: Associative array of state
**Usage**:
```php
protected function getState(): array
{
return [
'userId' => $this->userId,
'filters' => $this->filters,
'page' => $this->page
];
}
```
---
##### `protected function setState(array $state): void`
Restore component state.
**Parameters**:
- `$state` - State array to restore
---
#### Real-Time Updates
##### `protected function enableSse(array $channels = []): void`
Enable Server-Sent Events for real-time updates.
**Parameters**:
- `$channels` - Channels to subscribe to (default: component-specific channel)
**Usage**:
```php
public function mount(): void
{
$this->enableSse([
'user.updates',
"team.{$this->teamId}.activity"
]);
}
```
---
##### `protected function broadcast(string $channel, array $data): void`
Broadcast update to all clients listening on channel.
**Parameters**:
- `$channel` - Channel name
- `$data` - Data to broadcast
**Usage**:
```php
#[LiveAction]
public function updateStatus(string $status): void
{
$this->status = $status;
// Broadcast to all team members
$this->broadcast("team.{$this->teamId}.updates", [
'type' => 'status_changed',
'user' => $this->user->name,
'status' => $status
]);
}
```
---
#### Static Factory
##### `public static function mount(string $componentClass, array $initialData = []): string`
Create and render component.
**Parameters**:
- `$componentClass` - Fully qualified class name
- `$initialData` - Initial data for component
**Returns**: Rendered component HTML
**Usage**:
```php
// In controller
public function dashboard(): ViewResult
{
return new ViewResult('dashboard', [
'statsWidget' => LiveComponent::mount(StatsWidget::class, [
'user_id' => $currentUser->id
])
]);
}
```
---
## Attributes
### `#[LiveProp]`
Marks a property for automatic state synchronization.
**Usage**:
```php
use App\Framework\LiveComponents\Attributes\LiveProp;
final class SearchComponent extends LiveComponent
{
#[LiveProp]
public string $searchTerm = '';
#[LiveProp]
public array $filters = [];
#[LiveProp]
public int $page = 1;
}
```
**Options**:
- Properties are automatically serialized/deserialized
- Two-way binding with `data-lc-model`
- State preserved across requests
---
### `#[LiveAction]`
Marks a method as a LiveComponent action.
**Usage**:
```php
use App\Framework\LiveComponents\Attributes\LiveAction;
#[LiveAction]
public function search(): void
{
$this->results = $this->searchService->search($this->searchTerm);
}
#[LiveAction]
public function addToCart(string $productId): void
{
$this->cart->add($productId);
}
```
**Callable From Client**:
```html
```
---
### `#[Fragment(string|array $names)]`
Marks action to only update specific fragments.
**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Fragment;
#[LiveAction]
#[Fragment('search-results')]
public function search(): void
{
$this->results = $this->searchService->search($this->searchTerm);
// Only search-results fragment re-renders
}
#[LiveAction]
#[Fragment(['user-stats', 'activity-feed'])]
public function refreshDashboard(): void
{
$this->updateStats();
$this->loadActivity();
// Both fragments re-render
}
```
---
### `#[RateLimit(int $requests, int $window)]`
Apply rate limiting to component or action.
**Usage**:
```php
use App\Framework\LiveComponents\Attributes\RateLimit;
#[RateLimit(requests: 10, window: 60)]
final class SearchComponent extends LiveComponent
{
#[LiveAction]
#[RateLimit(requests: 5, window: 60)]
public function expensiveSearch(): void
{
// Limited to 5 requests per minute
}
}
```
---
### `#[Authorize(array $roles = [], array $permissions = [])]`
Require authorization for action.
**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Authorize;
#[LiveAction]
#[Authorize(roles: ['admin'])]
public function deleteUser(string $userId): void
{
$this->userService->delete($userId);
}
#[LiveAction]
#[Authorize(permissions: ['users.edit'])]
public function updateUserRole(string $userId, string $role): void
{
$this->userService->updateRole($userId, $role);
}
```
---
### `#[Idempotent]`
Ensure action executes exactly once (for critical operations).
**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Idempotent;
#[LiveAction]
#[Idempotent]
public function processPayment(): void
{
$this->paymentGateway->charge($this->amount);
$this->orderService->createOrder($this->cartItems);
// Guaranteed to execute only once even if request duplicated
}
```
---
### `#[Encrypted]`
Encrypt property value in client state.
**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Encrypted;
final class PaymentForm extends LiveComponent
{
#[LiveProp]
#[Encrypted]
public string $creditCardNumber = '';
#[LiveProp]
#[Encrypted]
public string $cvv = '';
#[LiveProp] // Not encrypted - safe to expose
public string $cardholderName = '';
}
```
---
### `#[Optimistic(string $property, string $operation)]`
Enable optimistic UI updates for action.
**Usage**:
```php
use App\Framework\LiveComponents\Attributes\Optimistic;
#[LiveAction]
#[Optimistic(property: 'isLiked', operation: 'toggle')]
#[Optimistic(property: 'likeCount', operation: 'increment')]
public function toggleLike(): void
{
$this->isLiked = !$this->isLiked;
$this->likeCount += $this->isLiked ? 1 : -1;
}
```
**Operations**:
- `toggle` - Boolean toggle
- `increment` - Increment number
- `decrement` - Decrement number
- `set` - Set to specific value
---
## HTTP Integration
### LiveComponent HTTP Endpoint
**POST** `/livecomponent/{componentId}/{action}`
Execute a LiveComponent action.
**Request Headers**:
```http
Content-Type: application/json
X-CSRF-Token: {token}
X-Component-Checksum: {checksum}
```
**Request Body**:
```json
{
"state": {
"searchTerm": "laptop",
"filters": ["electronics"],
"page": 1
},
"params": {
"productId": "123"
}
}
```
**Response**:
```json
{
"success": true,
"html": "
...
",
"fragments": {
"search-results": "...
"
},
"redirect": null,
"events": []
}
```
---
### Batch Endpoint
**POST** `/livecomponent/{componentId}/batch`
Execute multiple actions in single request.
**Request Body**:
```json
{
"batch": [
{
"action": "incrementCounter",
"params": {}
},
{
"action": "updateName",
"params": {"name": "John"}
},
{
"action": "save",
"params": {}
}
],
"state": {
"count": 0,
"name": ""
}
}
```
**Response**:
```json
{
"success": true,
"results": [
{ "success": true, "html": "..." },
{ "success": true, "html": "..." },
{ "success": true, "html": "..." }
]
}
```
---
### Upload Endpoint
**POST** `/livecomponent/{componentId}/upload`
Upload file chunks.
**Request Headers**:
```http
Content-Type: multipart/form-data
X-Upload-ID: {unique-upload-id}
X-Chunk-Index: {chunk-number}
X-Total-Chunks: {total-chunks}
```
**Response**:
```json
{
"success": true,
"chunk_index": 0,
"received_bytes": 1048576,
"complete": false
}
```
---
### SSE Endpoint
**GET** `/livecomponent/sse/{componentId}`
Subscribe to Server-Sent Events.
**Response** (text/event-stream):
```
event: component-update
data: {"type":"fragment","fragment":"user-stats","html":"...
"}
event: component-update
data: {"type":"full","html":"...
"}
event: heartbeat
data: {"timestamp":1634567890}
```
---
## JavaScript API
### `LiveComponent` Global Object
Main JavaScript interface for LiveComponents.
#### Methods
##### `LiveComponent.mount(element: HTMLElement): void`
Initialize component on element.
**Usage**:
```javascript
const componentEl = document.querySelector('[data-component-id="abc123"]');
LiveComponent.mount(componentEl);
```
---
##### `LiveComponent.unmount(componentId: string): void`
Destroy component and clean up resources.
**Usage**:
```javascript
LiveComponent.unmount('abc123');
```
---
##### `LiveComponent.executeAction(componentId: string, action: string, params: object): Promise`
Manually execute component action.
**Usage**:
```javascript
await LiveComponent.executeAction('abc123', 'search', {
query: 'laptops'
});
```
---
##### `LiveComponent.getComponent(componentId: string): Component | null`
Get component instance.
**Returns**: Component object or null
**Usage**:
```javascript
const component = LiveComponent.getComponent('abc123');
console.log(component.state);
console.log(component.name);
```
---
##### `LiveComponent.getState(componentId: string): object | null`
Get component state.
**Returns**: State object or null
**Usage**:
```javascript
const state = LiveComponent.getState('abc123');
console.log(state.searchTerm);
console.log(state.filters);
```
---
##### `LiveComponent.setState(componentId: string, state: object): void`
Update component state (triggers server sync).
**Usage**:
```javascript
LiveComponent.setState('abc123', {
searchTerm: 'new query',
page: 2
});
```
---
##### `LiveComponent.refresh(componentId: string): Promise`
Force component refresh from server.
**Usage**:
```javascript
await LiveComponent.refresh('abc123');
```
---
##### `LiveComponent.configure(options: object): void`
Configure global LiveComponent settings.
**Options**:
- `batchSize` - Max actions per batch (default: 10)
- `batchDebounce` - Debounce delay in ms (default: 50)
- `optimisticUI` - Enable optimistic updates (default: true)
- `csrfProtection` - Enable CSRF protection (default: true)
- `enableSSE` - Enable Server-Sent Events (default: true)
**Usage**:
```javascript
LiveComponent.configure({
batchSize: 15,
batchDebounce: 100,
optimisticUI: true
});
```
---
#### Properties
##### `LiveComponent.components: Map`
All active components.
**Usage**:
```javascript
console.log(`Active components: ${LiveComponent.components.size}`);
LiveComponent.components.forEach((component, id) => {
console.log(`${id}: ${component.name}`);
});
```
---
### Component Object
Individual component instance (returned by `getComponent()`).
#### Properties
```typescript
interface Component {
id: string; // Unique component ID
name: string; // Component class name
state: object; // Current state
element: HTMLElement; // DOM element
isConnected: boolean; // SSE connection status
isPending: boolean; // Has pending actions
}
```
---
### Data Attributes
#### `data-component-id`
Identifies component root element. **Required** on component container.
```html
```
---
#### `data-lc-model`
Two-way data binding for inputs.
```html
```
**Modifiers**:
- `data-lc-model.debounce.500="searchTerm"` - Debounce 500ms
- `data-lc-model.lazy="bio"` - Update on blur instead of input
---
#### `data-lc-action`
Trigger action on click.
```html
```
---
#### `data-lc-fragment`
Mark fragment for partial updates.
```html
```
---
#### `data-lc-submit`
Handle form submission.
```html
```
---
#### `data-optimistic`
Enable optimistic update for action.
```html
```
---
#### `data-lc-upload`
Enable chunked file upload.
```html
```
---
## Value Objects
### `ComponentId`
Unique component identifier.
```php
final readonly class ComponentId
{
public function __construct(public string $value) {}
public static function generate(): self
{
return new self(bin2hex(random_bytes(16)));
}
public function toString(): string
{
return $this->value;
}
}
```
---
### `ComponentState`
Component state snapshot.
```php
final readonly class ComponentState
{
public function __construct(
public array $properties,
public string $checksum
) {}
public function toArray(): array
{
return $this->properties;
}
public function verify(string $checksum): bool
{
return hash_equals($this->checksum, $checksum);
}
}
```
---
### `FragmentName`
Fragment identifier.
```php
final readonly class FragmentName
{
public function __construct(public string $value) {}
public static function fromString(string $name): self
{
return new self($name);
}
}
```
---
## Services
### `LiveComponentManager`
Core service for component lifecycle management.
```php
final readonly class LiveComponentManager
{
public function create(
string $componentClass,
array $initialData = []
): LiveComponent;
public function hydrate(
string $componentClass,
ComponentId $id,
ComponentState $state
): LiveComponent;
public function executeAction(
LiveComponent $component,
string $actionName,
array $params = []
): ActionResult;
public function render(LiveComponent $component): string;
public function renderFragment(
LiveComponent $component,
FragmentName $fragment
): string;
}
```
---
### `LiveComponentState`
State management service.
```php
final readonly class LiveComponentState
{
public function serialize(LiveComponent $component): ComponentState;
public function deserialize(
string $componentClass,
array $state
): LiveComponent;
public function generateChecksum(array $state): string;
public function verifyChecksum(array $state, string $checksum): bool;
}
```
---
## Events
### Client-Side Events
#### `livecomponent:mount`
Fired when component is mounted.
```javascript
window.addEventListener('livecomponent:mount', (e) => {
console.log('Component mounted:', e.detail);
// { componentId, name, element }
});
```
---
#### `livecomponent:action-start`
Fired when action starts.
```javascript
window.addEventListener('livecomponent:action-start', (e) => {
console.log('Action starting:', e.detail);
// { componentId, action, params, optimistic }
});
```
---
#### `livecomponent:action-executed`
Fired when action completes.
```javascript
window.addEventListener('livecomponent:action-executed', (e) => {
console.log('Action completed:', e.detail);
// { componentId, action, duration, success }
});
```
---
#### `livecomponent:action-error`
Fired when action fails.
```javascript
window.addEventListener('livecomponent:action-error', (e) => {
console.error('Action failed:', e.detail);
// { componentId, action, error, response }
});
```
---
#### `livecomponent:fragment-updated`
Fired when fragment updates.
```javascript
window.addEventListener('livecomponent:fragment-updated', (e) => {
console.log('Fragment updated:', e.detail);
// { componentId, fragmentName, duration, nodesChanged }
});
```
---
#### `livecomponent:batch-sent`
Fired when batch request is sent.
```javascript
window.addEventListener('livecomponent:batch-sent', (e) => {
console.log('Batch sent:', e.detail);
// { componentId, actionsCount, payloadSize }
});
```
---
#### `livecomponent:optimistic-applied`
Fired when optimistic update is applied.
```javascript
window.addEventListener('livecomponent:optimistic-applied', (e) => {
console.log('Optimistic update:', e.detail);
// { componentId, action, stateBeforeOptimistic }
});
```
---
#### `livecomponent:optimistic-rollback`
Fired when optimistic update is rolled back.
```javascript
window.addEventListener('livecomponent:optimistic-rollback', (e) => {
console.warn('Optimistic rollback:', e.detail);
// { componentId, action, error, stateBeforeOptimistic }
});
```
---
#### `livecomponent:sse-connected`
Fired when SSE connection established.
```javascript
window.addEventListener('livecomponent:sse-connected', (e) => {
console.log('SSE connected:', e.detail);
// { componentId, channels }
});
```
---
#### `livecomponent:sse-disconnected`
Fired when SSE connection lost.
```javascript
window.addEventListener('livecomponent:sse-disconnected', (e) => {
console.warn('SSE disconnected:', e.detail);
// { componentId, reason }
});
```
---
#### `livecomponent:error`
Fired on any LiveComponent error.
```javascript
window.addEventListener('livecomponent:error', (e) => {
console.error('LiveComponent error:', e.detail);
// { componentId, type, message, code }
if (e.detail.code === 'CSRF_TOKEN_EXPIRED') {
LiveComponent.refreshCsrfToken();
}
});
```
---
### Server-Side Events
Events dispatched during server-side processing (integrate with framework Event System).
#### `ComponentMountedEvent`
```php
final readonly class ComponentMountedEvent
{
public function __construct(
public string $componentClass,
public ComponentId $componentId,
public array $initialData
) {}
}
```
---
#### `ComponentActionExecutedEvent`
```php
final readonly class ComponentActionExecutedEvent
{
public function __construct(
public string $componentClass,
public ComponentId $componentId,
public string $actionName,
public array $params,
public float $duration,
public bool $success
) {}
}
```
---
#### `ComponentUnmountedEvent`
```php
final readonly class ComponentUnmountedEvent
{
public function __construct(
public string $componentClass,
public ComponentId $componentId
) {}
}
```
---
## Error Handling
### Common Errors
#### `ComponentNotFoundException`
Component class not found.
```php
throw ComponentNotFoundException::forClass('App\\Components\\NonExistent');
```
---
#### `ActionNotFoundException`
Action method not found on component.
```php
throw ActionNotFoundException::forAction('nonExistentAction', $componentClass);
```
---
#### `InvalidStateException`
Component state invalid or corrupted.
```php
throw InvalidStateException::checksumMismatch($expectedChecksum, $actualChecksum);
```
---
#### `RateLimitExceededException`
Rate limit exceeded for component/action.
```php
throw RateLimitExceededException::forAction($actionName, $retryAfter);
```
---
#### `UnauthorizedException`
User not authorized for action.
```php
throw UnauthorizedException::missingRole($requiredRole);
throw UnauthorizedException::missingPermission($requiredPermission);
```
---
## Type Definitions
### TypeScript Definitions
For TypeScript projects:
```typescript
// livecomponents.d.ts
declare global {
interface Window {
LiveComponent: {
mount(element: HTMLElement): void;
unmount(componentId: string): void;
executeAction(
componentId: string,
action: string,
params?: object
): Promise;
getComponent(componentId: string): Component | null;
getState(componentId: string): object | null;
setState(componentId: string, state: object): void;
refresh(componentId: string): Promise;
configure(options: LiveComponentConfig): void;
components: Map;
};
}
interface Component {
id: string;
name: string;
state: object;
element: HTMLElement;
isConnected: boolean;
isPending: boolean;
}
interface LiveComponentConfig {
batchSize?: number;
batchDebounce?: number;
optimisticUI?: boolean;
csrfProtection?: boolean;
enableSSE?: boolean;
}
}
export {};
```
---
**Next**: [Advanced Features](advanced-features.md) →