Pages
Pages are the foundation of Spark applications. Each page handles a route, loads data, and renders HTML on the server.
The @Page Annotation
Use the `@Page` annotation to define a route for your page.
@Page(path: '/users/:id')
class UserPage extends SparkPage<User> {
// ...
}Path parameters use the `:param` syntax. The `methods` parameter defaults to `['GET']` but can accept multiple methods.
The Generic Type
SparkPage uses a generic type `<T>` for type-safe data flow between `loader()` and `render()`. Use `void` for pages that don't load data.
// Page with data
class UserPage extends SparkPage<User> { ... }
// Page without data
class AboutPage extends SparkPage<void> { ... }The loader() Method
The `loader()` method fetches data before rendering. It returns a `PageResponse<T>`.
@override
Future<PageResponse<User>> loader(PageRequest request) async {
final id = request.pathParamInt('id');
final user = await fetchUser(id);
if (user == null) {
return PageError.notFound('User not found');
}
return PageData(user);
}PageResponse Types
The loader can return three types of responses:
// Success - pass data to render()
return PageData(user);
// Redirect to another page
return PageRedirect('/login');
return PageRedirect.permanent('/new-url'); // 301
// Error response
return PageError('Something went wrong');
return PageError.notFound(); // 404
return PageError.forbidden(); // 403
return PageError.badRequest(); // 400The render() Method
The `render()` method generates HTML using the Element DSL. It receives the loaded data and returns an `Element`.
@override
Element render(User data, PageRequest request) {
return div([
h1([data.name]),
p(['Email: ${data.email}']),
]);
}PageRequest Helpers
Access request data using typed helpers:
// Path parameters
final id = request.pathParamInt('id');
final slug = request.pathParam('slug');
// Query parameters
final page = request.queryParamInt('page', 1);
final search = request.queryParam('q');
// Headers and cookies
final token = request.header('authorization');
final session = request.cookie('session_id');Optional Overrides
Customize your page with these optional overrides:
// Page title
@override
String title(User data, PageRequest request) =>
'${data.name} - Profile';
// Route middleware
@override
List<Middleware> get middleware => [authMiddleware()];
// Inline styles
@override
Stylesheet? get inlineStyles => css({ ... });
// Interactive components
@override
List<ComponentInfo> get components => [
ComponentInfo('my-counter', Counter.new),
];