Quick start
This page wires both halves in a Symfony application with the bundle registered (see Installation).
1. Start the handler
Section titled “1. Start the handler”In your JavaScript entry point, give TurboHandler the functions that set up and tear down your widgets (tooltips,
selects, date pickers…) inside a container:
// assets/app.js (assets/app.ts with TypeScript)import '@hotwired/turbo'import { TurboHandler } from '@silarhi/turbo'
const handler = new TurboHandler({ onMount: (container) => app.mount(container), onUnmount: (container) => app.unmount(container),})
handler.start() // attach listeners (idempotent)// handler.stop() // detach them all and resetapp.mount() and app.unmount() stand for your own code. TurboHandler decides when and on which element they
run: the <body> on the first page load and after each Drive render, a frame after it loads, the nodes a Turbo Stream
inserted or removed. Details: TurboHandler.
2. Redirect out of a frame
Section titled “2. Redirect out of a frame”Without the bundle, a form inside a <turbo-frame> that redirects after a successful submit makes Turbo load the
redirect target inside the frame. With the bundle and the handler, the redirect becomes a full page visit:
<turbo-frame id="project-edit"> {{ form(form) }}</turbo-frame>#[Route('/projects/{id}/edit', name: 'project_edit')]public function edit(Project $project, Request $request): Response{ // ... handle the form if ($form->isSubmitted() && $form->isValid()) { return $this->redirectToRoute('project_show', ['id' => $project->getId()]); }
return $this->render('project/edit.html.twig', ['form' => $form]);}- FramePOST /projects/1/edit
- Controller302, Location: /projects/1
- TurboFrameListener204, Turbo-Location: /projects/1
- TurboHandlerTurbo.visit('/projects/1')
The controller stays unaware of Turbo. To keep a frame’s redirects inside it, add data-turbo-follow-redirect to the
frame: see Keeping a redirect in its frame.
3. Render a lean template inside frames
Section titled “3. Render a lean template inside frames”With the turbo_frame filter, the same action renders the full page on a normal request and a lean layout when a
frame asks for it:
{# templates/project/edit.html.twig #}{% extends 'base.html.twig'|turbo_frame('project-edit') %}Inside the project-edit frame, the template extends base-frame.html.twig instead of base.html.twig: the filter
looks for the -frame sibling of the template first, then falls back to the configured base_template (also
base-frame.html.twig by default). Create that layout, or frame requests fail with “Unable to find template”. It
needs a <turbo-frame> with the id of the requesting frame, and the blocks your pages fill:
{# templates/base-frame.html.twig #}<turbo-frame id="{{ app.request.headers.get('Turbo-Frame') }}"> {% block body %}{% endblock %}</turbo-frame>