Skip to content

Getting Started

This guide builds a single page from PHP and registers a route for it. It assumes you have completed Installation.

A page extends Lattice\Lattice\Http\Page. It returns a title() and builds its UI in render() by populating the PageSchema with components.

<?php
namespace App\Pages;
use Lattice\Lattice\Attributes\AsPage;
use Lattice\Lattice\Ui\Components\Card;
use Lattice\Lattice\Ui\Components\Grid;
use Lattice\Lattice\Ui\Components\Heading;
use Lattice\Lattice\Ui\Components\Stack;
use Lattice\Lattice\Ui\Components\Text;
use Lattice\Lattice\Ui\Enums\Gap;
use Lattice\Lattice\Ui\Enums\PageLayout;
use Lattice\Lattice\Core\PageSchema;
use Lattice\Lattice\Http\Page as BasePage;
#[AsPage(route: '/dashboard', layout: PageLayout::None, middleware: ['web'])]
final class DashboardPage extends BasePage
{
public function title(): string
{
return 'Dashboard';
}
public function render(PageSchema $schema): PageSchema
{
return $schema->schema([
Stack::make('dashboard')
->gap(Gap::Large)
->schema([
Heading::make('Dashboard'),
Text::make('Everything below is described in PHP and rendered as React.'),
Grid::make('stats')
->columns(2)
->schema([
Card::make('Orders', '128 this week.'),
Card::make('Revenue', '$4,210 this week.'),
]),
]),
]);
}
}

There is no route file entry to write. Lattice scans the paths in lattice.discover (app/ by default), finds every class carrying a #[AsPage] attribute, and registers a route for it automatically. The route name auto-derives from the URI (/dashboarddashboard); supply name: in the attribute to override it.

Visit /dashboard and the page renders through Inertia — no route file entry, no controller, and no Inertia page component to write by hand.

Sharing layout and middleware across pages

Section titled “Sharing layout and middleware across pages”

Rather than repeating layout: and middleware: on every page, declare a shared base page and inherit from it:

use Lattice\Lattice\Attributes\AsPage;
use Lattice\Lattice\Ui\Enums\PageLayout;
use Lattice\Lattice\Http\Page as BasePage;
#[AsPage(layout: PageLayout::App, middleware: ['web'])]
abstract class AppPage extends BasePage {}
#[AsPage(route: '/dashboard')] // inherits layout + web middleware
final class DashboardPage extends AppPage { /* title(), render() */ }

Pages need the web middleware group for sessions, CSRF, and route-model binding. Setting it once on the shared base keeps individual pages clean.

To register pages explicitly — for example from a package — call Lattice::pages([DashboardPage::class]) in a service provider instead of relying on discovery.

Navigation (sidebar and menus) is built from Menu and Sidebar layout components in PHP. See Navigation for details.