Rendering and Preview Workflow
Input contract
The rendering layer expects:
structurecontextlayout_variant- optional entity metadata for some preview flows
The structure is always:
{ "body": { ... }, "components": [ ... ] }
Main render entry point
The normal entry point is:
BuilderApiController::render() (handles POST /tagixo/builder/render), which dispatches to the appropriate renderer via BuilderApiService::render(structure, context, layoutVariant, entityType, entityId).
Render branches
- Form context -> form preview renderer path
- Page + carousel variant -> carousel preview branch
- Default -> page renderer path
This branch selection is not cosmetic. The same data can produce different output depending on context and variant.
Default page path
The default path goes through PageRenderer::renderFromJson().
At a high level, it:
- normalizes structure
- rebuilds node hierarchy if needed
- renders modules through Blade views
- generates CSS through PropTypes and the style generator
- returns
html,css, and optionalfonts
This is the path you will use most often for page-like output.
Public page layout assembly
When you render a real public page, there is an additional layout-aware step:
PageRenderer::renderWithLayout(Page $page)
That step:
- resolves the page layout
- renders page body independently
- prepends header when available
- appends footer when available
- falls back per section to the global default layout when assigned layout sections are missing
Important:
bodybelongs to the page itselfheaderandfooterbelong to layouts- fallback is section-based, not whole-layout based
Native rendering helpers on built-in models
For consumers that use the package's Page, MailTemplate, and PdfTemplate Eloquent models, three helper methods on the models bake the full HTML+CSS+fonts result in one call — useful for cron jobs, mail dispatch, and PDF generation pipelines:
Page::renderFull(): string— returns the complete public HTML document (DOCTYPE + head + CSS + fonts + body) for the page. This is whatPublicPageControllercalls when serving/{path?}.MailTemplate::renderHtml(array $data = []): string— produces an email-ready HTML body (inline CSS where reasonable, restricted module set). Pass$datafor variable substitution.PdfTemplate::renderHtml(array $data = []): string— produces print-ready HTML. Pair withdompdf/dompdf(or any PDF engine) for the binary output.
These bypass the live builder pipeline and work directly off the persisted content JSON, so they are safe to call from queued jobs without booting any builder admin UI.
If your project uses custom Eloquent models instead of the package ones, replicate the pattern by injecting the appropriate renderer (PageRenderer, MailRenderer, PdfRenderer) and calling renderFromJson() against your stored structure.
Form preview path
When context=form, Tagixo uses a form-specific preview renderer.
That renderer:
- interprets form modules and wrappers differently from page content modules
- outputs embeddable form markup
- combines component CSS with global variables
If you test a form payload through page assumptions, your output will look broken even if the saved data is valid.
Carousel preview path
When context=page and layout_variant=carousel, Tagixo switches to slider preview logic.
That logic:
- renders a baseline structure first
- extracts root sections as slides
- resolves transition settings, autoplay delay, navigation, and pagination
- wraps output in a dedicated carousel preview view
This is why slider support should be documented as a page variant, not as a separate context.
Preview URL flow
The preview flow is intentionally server-mediated and uses signed URLs (no cached payload):
- editor posts
{context, entity_id}toPOST /tagixo/builder/preview-url - backend returns
{preview_url, expires_in}— for page context the URL points at the entity's public slug; for mail/pdf it points at/tagixo/builder/preview-{mail|pdf}/{id} - opening the URL hits the relevant renderer, which checks signature +
_preview=1+ authenticated session before bypassing thepublished()gate
This gives you:
- short-lived preview access (TTL via
tagixo.preview.url_ttl_seconds) - user/session binding (auth required even with valid signature)
- no token bookkeeping — the signature is the credential
- consumer-side honour: your
PublicPageControllerusesPage::isAuthorizedPreviewRequest($request)to honour the bypass forcontext=page
Why context discipline matters
Always keep context and layout_variant explicit when:
- previewing
- server-side rendering
- exporting
- caching render artifacts
Do not "guess" context at the edge of your system.
Debug checklist
- Route receives expected
context/layout_variant. - Module exists in bootstrap
availableComponents. - Module view resolves correctly.
- Prop shape matches expected schema.
- Generated CSS contains expected groups.
Output contract
The render API returns:
htmlcssfontswhen relevant
Your host UI is responsible for injecting css and fonts correctly in preview contexts.
Production recommendations
In production, cache rendered artifacts per entity revision and invalidate only when content changes.
If your app renders high-traffic public pages, do not rebuild full output on every public request unless you have measured and accepted that cost.