SPA Experience
Lacelium features an integrated zero-configuration Single Page Application engine. By intercepting internal link clicks and form submissions, it provides instantaneous transitions without full page reloads, preserving DOM state and providing native browser history support.
How It Works
When an internal hyperlink is clicked, Lacelium's frontend router intercepts the event, triggers a top loading bar, and fetches the target HTML via an asynchronous request. It automatically extracts the dynamic container (#lacelium-main), performs an atomic DOM morph, and updates the URL using the HTML5 pushState API.
Zero Build Tools Required
Unlike heavy client-side frameworks (React, Vue, or Angular), Lacelium's SPA architecture requires no JavaScript build steps, bundlers, or hydration overhead. All rendering remains server-side in Twig.
Interactive Simulation
Test the transition lifecycle below to see how atomic DOM swapping and progress indicators operate:
#lacelium-main)
Declarative Navigation Attributes
Fine-tune how individual links and forms behave directly from HTML data attributes:
| Attribute | Target Element | Behavior Description |
|---|---|---|
data-lacelium-refresh |
<a>, <form> |
Opt-out of SPA navigation. Triggers a full browser reload (useful for file exports or third-party OAuth links). |
data-lacelium-redirect |
<button>, <div> |
Instructs the router to execute a programmatic client-side pushState redirect to the specified URL. |
data-lacelium-target |
<a> |
Specifies a custom container selector to update instead of the default #lacelium-main. |
Seamless Form Submissions
Forms submit asynchronously through Lacelium's SPA transport layer. When a controller action returns a JSON response containing a redirect key, the client automatically executes a smooth transition:
namespace App\Http\Controllers;
use Lacelium\Core\Http\Request;
use Lacelium\Core\Http\Response;
class SettingsController
{
public function update(Request $request, Response $response): Response
{
// 1. Validate & persist changes...
// 2. Return SPA redirect instruction
return $response->json([
'success' => true,
'message' => 'Settings saved successfully',
'redirect' => '/dashboard',
]);
}
}
JavaScript Lifecycle Hooks
Listen for custom DOM events to re-initialize client-side libraries (like tooltips, popovers, syntax highlighters, or charts) whenever navigation occurs:
// Fired before an asynchronous navigation request starts
document.addEventListener('lacelium:before-load', function (event) {
console.log('Navigating to:', event.detail.url);
});
// Fired immediately after the DOM container has been replaced
document.addEventListener('lacelium:content-replaced', function () {
console.log('DOM swapped! Re-initializing dynamic widgets...');
// Re-initialize tooltips or charts
if (window.bootstrap && bootstrap.Tooltip) {
document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(el => new bootstrap.Tooltip(el));
}
});
// Fired after the transition is complete and progress bar ends
document.addEventListener('lacelium:after-load', function () {
window.scrollTo({ top: 0, behavior: 'instant' });
});
Production Guidelines
- Persistent Top Layout: Keep heavy dependencies (such as navigation bars, stylesheets, and global scripts) outside the dynamic dynamic target container so they remain in memory.
- Memory Management: Disconnect any orphaned Nexify channel subscriptions or intervals inside the
lacelium:before-loadlistener before switching views. - Progressive Enhancement: Always ensure hyperlinks point to genuine HTTP routes so search engine crawlers and users with JavaScript disabled experience zero breakage.
Next Steps
- Connect real-time full-duplex event streaming in Nexify Real-Time.
- Build server-driven modal dialogs in Modal System.
- Map incoming client requests to controllers in Routing Engine.