Premise
On top of pausing rendering and resuming it (see previous challenge), Turbo Drive also exposes a render method to overwrite in the turbo:before-render
event. Using the current and new body element, you can use this to provide a custom segue between the two.
Browse through the page_renderer source to get an idea of how this is done in the default implementation:
- Check if the requested page will render. This is generally true, except for a redirect, for example.
- Replace the body, while preserving permanent elements.
- To do this, first activate it, by adopting the new body into the DOM
- Finally render the new element.
The Turbo guide uses morphdom as a replacement mechanism, but you are of course free to implement any custom logic here.
🐉 Here be dragons! Be aware that now you are fully in charge to implement the page transition on your own, including edge cases like activating new script elements.
Starting Point
The following StackBlitz example includes two pages (index.html and page2.html) each containing an image and a <ul>
acting as a simple navigation. In app.js, there’s some boilerplate code introducing a turbo:before-render
event listener. The event.detail.render
method you have to implement is already stubbed out. Your challenge is to fork this StackBlitz project and code your own rendering solution. Look below for some challenges you could tackle.
By the way, to add a certain JavaScript package to your importmaps, you can use https://generator.jspm.io/.
Challenges
- Can you swap out the navigation, but add a nice image transition? (below is an example GIF of how that could look using fancy css filters and GSAP.)
- Try to implement morphdom, and explore all the options (including
onElUpdated
and other callbacks) - Try to add a third page. Does your implementation still work?
Caveats
- Again, you have to deal with cache restoration visits. Check
<html data-turbo-preview>
or opt out of caching altogether.
Teasers
In your app, this could be implemented in a custom stimulus controller, for example, and put onto the body element:
<body data-controller="image-transition" data-action="turbo:before-render->image-transition#swap">
export default class extends Controller {
swap(event) {
event.detail.render = (currentElement, newElement) => {
// rendering logic
}
}
}
This way, you could also parameterize the rendering logic by adding Stimulus values to the controller.