Skip to main content
Pages are server-rendered Twig, made interactive with Alpine.js. There’s no separate single-page application: each page ships the markup it needs plus a small bundle.

The Twig environment

The loader is set up with these paths, in order: Because overrides is first, a template placed there wins over the original of the same path. Extensions: Intl, gettext, Markdown, plus the application’s own functions and the theme asset filter. The environment also exposes an env global holding the raw environment.
env contains credentials. A template may read one key from it, but it must never be dumped or serialized into the page.

Rendering a view

A handler returns a ViewResponse, which ViewMiddleware renders:
The middleware merges the handler’s data with a set of globals, so every view has the same context: Theme templates receive the same set. See Template objects.

Layouts

main.twig defines the blocks pages fill in, including template for content, layout for full-screen pages, and styles and scripts for extra assets. Plugin pages extend it. See Frontend integration.

The frontend build

Vite builds several entry points: Output goes to public/ with a manifest at public/.vite/manifest.json, and resources/static is copied to the web root as-is. Templates resolve built files with the asset filter, which reads that manifest, or points at the dev server when HMR is enabled.

Interactivity

Alpine.js provides component behavior:
main.twig binds the page to the named Alpine component, which is registered in the relevant bundle. Shared behavior is packaged as custom elements, such as x-form, x-money, x-avatar, x-copy and modal-element, and as globals: an API client, a modal controller and a toast service. The client talks to the JSON API rather than posting forms, which is why most admin pages are a Twig shell plus an Alpine component calling /admin/api/....

Overriding a core template

resources/views/overrides/ doesn’t exist by default. Create it, mirror the path of the template you want to change, and edit the copy:
The directory isn’t part of the release archive, so updates keep it. They do update the originals, though, and your copy won’t pick up those changes.
Every override is a fork of one file. Keep them few, and compare each one against the updated original after every release.

Emails

Email templates live in resources/emails under the @emails namespace, and are rendered by the mail service. See Email.