Skip to content

Last updated: First published:

The Turn-Signal

Backward/forward view transitions for intuitive history navigation.

The Turn-Signal is a lightweight script for purely progressive enhancement of cross-document view transitions. It detects the direction of browser navigation and signal it with view transition types or html attributes to guide directional styling. This enables developers to create smooth, responsive transitions that adjust based on forward or backward navigation, delivering a more intuitive user experience.

PREREQUISITE

Demo

Turn-Signal Demo

Animation detailsAnimation details

Check out the Turn-Signal Demo to see the Turn-Signal in action. Click the link to move to the next page, then use your browser’s back button to return. Notice how the slide animation changes direction based on your navigation.

Installation

To use the Turn-Signal, you can install the npm package in your project. Alternatively you can load the script from one of the global content delivery networks that provide npm packages.

  1. Install @vtbag/turn-signal from npm.
  2. In your project, add @vtbag/turn-signal/index.js as an inline script at the beginning of the <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 signal from "@vtbag/turn-signal?url";
<html>
<head>
<script src={signal} />
...
</head>
...
</html>

Forced Traversal

@vtbag/turn-signal also defines a second script that can be used with the main functionality or independent of it: It is called forced-traversal and 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.

The forced-traversal feature is not covered by the example above. But the there is another demo on the astro-vtbot-website that demonstrates the replacement.

Use this script in the same way as the main script by inserting it inside the <head>.

import forcedTraversal from "@vtbag/turn-signal/forced-traversal?url"
...
<script src={forceTraversal} />
</head>

There are no configuration options and the forced-traversal script does not take any parameters.

Configuration and Usage

@vtbag/turn-signal main script accepts 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

  • sets the backward view transition type if it detects backwards history traversals.
  • For navigation to the current page, it sets a view transition type called same.
  • For all other navigation, the forward type is set.

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 CSS selectors. 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 fit for all Starlight sites.

For a detailed description of data-selector and on how to instruct Turn-Style to set different types or even set attributes on the root element, see the config options below.

Let’s see how you can use these view transition types to style different animations dependent on the direction of the navigation or even switch transition groups on and off.

CSS for Reverse Animation

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.

Example for forward animations
::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 …

Example for fitting backward animations
: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.

Switching Transition Names

Transition types and direction attributes are determined 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!

How to switch off a view transition group based on direction
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 Turn-Signal also always sets view transition type old on the old page and new on the new page. So you can be even more specific:

How to switch off the old image, only
:active-view-transition-type(same):active-view-transition-type(old) main {
view-transition-name: none; /* but only a new image for links to the same page */
}

Config Options

Config optionTypeEffect
data-selectora CSS selector

If your site has a concept of previous and next page, use this to tell the Turn-Signal about your pages and their order. One selector to find them all.

The selector should return one element per page of your site, and each element must have an href attribute. Typically, you would select <a> elements from your navigation bar, such as data-selector="nav a".

If your site doesn’t already have a suitable structure, consider generating a list of pages in a non-intrusive way. For example, you could use <a> elements inside a <template> element or <link> elements with a custom rel attribute.

The sequence of selected URLs is used to derive the navigation direction. Navigation to a page that comes later in the sequence of selected URLs will be a forward navigation. Navigation to a page that comes earlier in the sequence of selected URLs will be a backward navigation.

data-direction-typesbackward-value, same-value, forward-value

The Turn-Signal sets view transition types to convey the derived direction in a form that can easily be used for styling your animations.

By default, the types are backward, same, and forward, i.e. as if set using data-direction-types="backward, same, forward".

An alternative would be data-direction-types="reverse,," This would do nothing for same page and forward navigation, but would set the reverse type on backward navigation.

On the old page, the Turn-Signal also sets a type called old and on the new page it sets a type called new. This behavior can not be customized.

data-direction-attributeattribute-name, backward-value, same-value, forward-value

For compatibility with existing code you might want to use attributes rather than view transition types to select different styling for your animations.

You can specify what attribute to use and what values to set. Here is an example of how to make Turn-Signal directions compatible with the CSS Astro generates for transition:animate: data-direction-attribute="data-astro-transition, back, forward, forward".