Version selector

This demo has several versions:

  1. Using 1 shared ScrollTimeline
  2. Using a ViewTimeline per entry

About this demo

This demo sports a little carousel. As you scroll the carousel, the markers also indicate which element you are viewing.

The Code / Explanation

The carousel consists of two child elements: a .scroller with the content and a .markers element that holds all markers.

<div data-component="carousel">
	<ul class="entries" tabindex="0">
		<li><a name="carousel_01"><img src="../shared/img/matroshka-01.svg" alt="" title="" width="222" height="184" draggable="false"></a></li>
	<ul class="markers">
		<li><a href="#carousel_01"><span class="sr-only">Photo 1</span></a></li>

The .scroller has its children laid out on a row, and has overflow-x: scroll applied on it. The .markers are position at the bottom of the carousel. Scroll snapping is used to make sure the carousel stops at a certain item instead of halfway.

Each entry is decorated with a view-timeline tracking its position within the scroller. The markers representing each item then use that value as their animation-timeline.

[data-component="carousel"] {
	.entries li:nth-child(1) {
		view-timeline: --entry1 inline;
	.entries li:nth-child(2) {
		view-timeline: --entry2 inline;
	.entries li:nth-child(3) {
		view-timeline: --entry3 inline;
	.entries li:nth-child(4) {
		view-timeline: --entry4 inline;
	.entries li:nth-child(5) {
		view-timeline: --entry5 inline;

	.markers li:nth-child(1) a {
		animation-timeline: --entry1;
	.markers li:nth-child(2) a {
		animation-timeline: --entry2;
	.markers li:nth-child(3) a {
		animation-timeline: --entry3;
	.markers li:nth-child(4) a {
		animation-timeline: --entry4;
	.markers li:nth-child(5) a {
		animation-timeline: --entry5;

Because timeline lookups only happen up the ancestor tree, the markers are not able to find the --entry-x timeline – the .entries element is not part of their ancestor tree. To allow the markers to use that timeline, timeline-scope is used on the [data-component="carousel"] itself to hoist up the declared --entry-x timelines, giving them a wider reach.

[data-component="carousel"] {
	timeline-scope: --entry1, --entry2, --entry3, --entry4, --entry5;

In the future, this can be simplified by declaring timeline-scope: all to pull up all contained timelines.

⚠️ Your browser does not support Scroll-driven Animations. Please use Chrome 115 or newer.