Link-Types Demo

Took a shiny Google demo and replaced their View Transition Toolkit with the Bag’s link-types script.
See the Link Types Demo to learn how link annotations control transition types and animations.
Last updated: First published:
Backward/forward view transitions for intuitive history navigation.
The Turn-Signal package is a set of scripts for enhancement of cross-document view transitions. They automatically detect the direction of navigation or let you explicitly set view transition types for a link. The current tricks are
The Turn-Signal scripts are designed for use with cross-document view transitions. With the exception of the forced_traversal script, all scripts will even work with none or only small limitations on browsers that do not support the Navigation API.
Link-Types Demo

Took a shiny Google demo and replaced their View Transition Toolkit with the Bag’s link-types script.
See the Link Types Demo to learn how link annotations control transition types and animations.
Turn-Signal Demo

Try the Turn-Signal Demo to see the directions script in action. Click on the icons to navigate the pages. Then use your browser’s back button to return.
Notice how the slide animation changes direction based on the order of the pages.
Image Viewer Demo
The Image Viewer Demo showcases various animations for the same page: sliding from right or left, resizing, and changing its aspect ratio.
Thanks to the link-types script, you can control which animation to use by adding annotations to the links that navigate to the page.
Fish Pond Demo
Looking for a more dramatic example of how to control view transition types with your links?
Check out the Fishpond Demo! Glide smoothly into the water or take a bold dive.
Explore the pond to learn more about how the demo was implemented.
Forced Traversal
To see the forced traversal script in action alongside the directions script, head over to the Vtbot Demo↗! No matter how many times you click the tabs in the header, your browser history will always have just three or less entries.
You can skip the Astro-specific details on the demo page. Script details are explained below
The scripts provided by the turn-signal package run entirely in the browser during navigation. Since they hook into events triggered early in the page load process, they must be included as classic JavaScript <script> elements within the <head> of any HTML page you want to enhance with these effects.
In other words, type="module" can’t be used because the deferred loading would make the script come too late to capture the early events.
All scripts are used the same way:
@vtbag/turn-signal from npm.<head> element on all pages of your site.Details depend on your project setup and the frameworks used, but with a bundler like vite it can be as simple as:
import signalDirections from "@vtbag/turn-signal/directions?url";<html> <head> <script src={signalDirections}></script> ... </head> ...</html>;The scripts offered by the turn-signal package are:
| Script | Module Specifier | Package Path |
|---|---|---|
| directions + link types | @vtbag/turn-signal | lib/index.js |
| same as above with debug output | @vtbag/turn-signal/debug | lib/debug.js |
| directions only | @vtbag/turn-signal/directions | lib/directions.js |
| link types only | @vtbag/turn-signal/link-types | lib/link-types.js |
| forced traversal | @vtbag/turn-signal/forced-traversal | lib/forced-traversal.js |
The scripts can be configured or guided by attributes on the script element itself or anchor elements in case of the link types script.
The @vtbag/turn-signal/directions script (and @vtbag/turn-signal script) accept several config options. Those are specified as data-* attributes on the <script> element. They are all optional.
If used without any explicit parameters, the Turn-Signal
backward view transition type if it detects backwards history traversals.same.forward type is set.old type is added, and on the new page the new type is added.If you want to tell the script about the order of the pages on your site, use the data-selector attribute to select links to all pages using a CSS selector. This site uses
<script ... data-selector="header a, nav.sidebar li a"></script>Here the first CSS selector selects the home page and the second all pages from the global site navigation. This selector will for example fit for all Starlight sites and the pattern can be adapted for sites with a similar main navigation.
If you install the link-types script, you can annotate every <a> element with view transition types!
The script finds anchor elements with a data-vtbag-link-types attribute and uses the identifiers to set up view transition types for that navigation. The value can be a space separated list of identifiers. Even better, you can have two or even three of those lists separated by a slash (/). If multiple lists are specified, they are used for backward history navigation and re-visits of the current page
| Pattern | Meaning |
|---|---|
| z | Use z for all navigation types |
| x/z | Use x for backward history traversals, and z for all other navigation types |
| x/y/z | Use x for backward history traversals, y for re-visits to the current page, and z for all other navigation types |
Like the directions script, the link types script also applies the old type to the old page and the new type to the new page.
The forced-traversal script replaces forward navigation with history traversals if the target pages has been visited before.
Users may be annoyed when a website messes up their history entries, but there are situations where replacing navigation with traversals has its appeal. Use at your own discretion.
There are no configuration options and the forced-traversal script does not take any parameters.
You can use the view transition types set by the scripts in your CSS to select different animations and other CSS properties. For information on the basic mechanisms see the styling page.
This example shows how to use a cross-fade effect by default and to replace that with a sliding animation iff a view transition type called shift-right is set.
::view-transition-old(main),::view-transition-new(main) { animation-duration: 200ms;}:active-view-transition-type(shift-right) { &::view-transition-old(main) { animation-name: slide-out-to-left; } &::view-transition-new(main) { animation-name: slide-in-from-right; }}That way you can have different animations for the same page depending on the specific user action.
Chances are more often then not that you can not simply revert the direction of your animation for the backward effect. Assume you have slideOutToLeft for the old image and slideInFromRight for the new image.
::view-transition-old(main) { animation-name: slideOutToLeft;}::view-transition-new(main) { animation-name: slideInFromRight;}
@keyframes slideOutToLeft { to { transform: translateX(-100%); }}@keyframes slideInFromRight { from { transform: translateX(100%); }}Just changing the direction of the animations would lead to something best named slideInFromLeft for the old image and slideOutToRight for the new image. While the animations are about right, just setting animation-direction: reverse would apply them to the wrong images. You do not want to slide in the old image or slide out the new image. So better you swap the keyframes, too…
:active-view-transition-type(backward) { &::view-transition-old(main) { animation-name: slideInFromRight; animation-direction: reverse; } &::view-transition-new(main) { animation-name: slideOutToLeft; animation-direction: reverse; }}…or even explicitly define keyframes for slideOutToRight and slideInFromLeft if you feel that is clearer.
…and you can also define different animations for :active-view-transition-type(same), i.e. for links to the current page, e.g. in a navigation bar by using the same pattern.
The scripts set transition types and direction attributes on the old page and the new page of the cross-document view transition. Even though CSS for animating cross-document view transitions is always taken from the new page, there is an important use case for directions on the old page: You can exclude elements from view transitions depending on the direction.
With directions on the old page you can not only exclude new images but also old images!
main { view-transition-name: main; /* for forward and backward slides */}
:active-view-transition-type(same) main { view-transition-name: none; /* but no transition for links to the same page */}The scripts also always sets view transition type old on the old page and new on the new page. So you can be even more specific:
:active-view-transition-type(same):active-view-transition-type(new) main { view-transition-name: none; /* but only an old image for links to the same page */}