DEV Community

Cover image for Creating Smooth Tab Transitions with the View Transitions API
Rodrigo Antunes
Rodrigo Antunes

Posted on

Creating Smooth Tab Transitions with the View Transitions API

TL;DR
The codepen is at the end of the post

Let's build this:
Smooth Tab Transition

⚠️Important

Before diving into how to make this, it's important to note that the View Transitions API is not yet fully supported in all browsers. At the time of writing, Firefox and Safari do not fully support this API. For users on unsupported browsers, we will provide a fallback method to ensure a consistent experience across different platforms.

View Transitions API Browser compatibility

HTML

Let's start by setting up the HTML structure for our tabs. It is a simple navigation bar with buttons:

<nav>
  <button> Explore </button>
  <button> Discover </button>
  <button> Navigate </button>
  <button> Journey </button>
  <button> Quest </button>
</nav>
Enter fullscreen mode Exit fullscreen mode

CSS (part 1/2)

Next, we'll add some CSS to style our navigation and create the tabbed interface. We'll use flexbox to organize the buttons horizontally and apply a custom underline effect.

The underline is actually a :after pseudo-element that gets applied to a element that have a .active class.

button {
  background: none;
  border: none;
  color: #fff;
  cursor: pointer;
  position: relative;
  font-size: 24px
}

/*  This is the underline element */
button.active:after {
  content: '';
  position: absolute;
  inset: 0 0 -8px 0;
  top: unset;
  height: 3px;
  background: #fff;
}
Enter fullscreen mode Exit fullscreen mode

Javascript (part 1/2)

Now, let's add some JavaScript to handle button click events and update the active tab accordingly:

const buttons = document.querySelectorAll('button');

buttons.forEach(button => {
  button.addEventListener('click', e => updateView(e))
});

const updateView = ({ target }) => {
  // Remove the .active class of all elements
  buttons.forEach(button => button.classList.remove('active'));
  // Add the .active class only to the clicked element
  target.classList.add('active');
}
Enter fullscreen mode Exit fullscreen mode

If we run the project, we have this:
Tabs with no animation
We are almost there 😅

CSS (part 2/2)

Here comes the wizardry 🧙
The view-transition-name property expects a string, any value that don't start with a number will do the job.

button.active:after {
  /* ... */
  view-animation-name: my-custom-transition; // unique name
}
Enter fullscreen mode Exit fullscreen mode

Javascript (part 2/2)

Here comes the wizardry² 🧙
The startViewTransition() method expects a callback function to make some good stuff:

  • Handle the loading and positioning of the old and new content.
  • Animate the old and new states to create the transition.
  • Stop accidental user interactions with the old content from causing problems.
  • Remove the old content once the transition is complete.
const buttons = document.querySelectorAll('button');

buttons.forEach(button => {
  button.addEventListener('click', (e) => {
    // Fallback, in case your browser
    // doesn't support startViewTransition
    if (!document.startViewTransition) {
      updateView(e);
      return
    }
    // tada 🪄
    document.startViewTransition(() => updateView(e))
  })
});

const updateView = ({ target }) => {
  buttons.forEach(item => item.classList.remove('active'));
  target.classList.add('active');
}
Enter fullscreen mode Exit fullscreen mode

There you have it 🎉

With the View Transitions API, we can create seamless animations between different views or states of your web application, enhancing the overall user experience.

Codepen:

Top comments (6)

Collapse
 
guiteixeira profile image
Guilherme Teixeira

AWESOME!!!!!!!!!!!!!!!!!!!!!!!!!!!

Collapse
 
phongpticdvn profile image
phongpticdvn

how about 'hover event', ex: mouseenter/mouseleave? I dont see any result in the Internet T_T

Collapse
 
rodrigoantunes profile image
Rodrigo Antunes • Edited

Hey @phongpticdvn, thanks for the message.
If you change the eventListener to mouseenter, it should work when hover the button, like this button.addEventListener('mouseenter', .... (on line 4)

But I'm not sure if that is what you need, you have an example to illustrate the effect you are trying to do?

Collapse
 
phongpticdvn profile image
phongpticdvn • Edited

I know that but the event i triggered continously, try it at: w3schools.com/tags/tryit.asp?filen...
with this script code:
const details = document.querySelector('details')
const summary = document.querySelector('summary')
summary.addEventListener('mouseenter', (event) => {
console.log(event)
event.preventDefault()
document.startViewTransition(() => {
details.setAttribute('open', '')
})
})

Thread Thread
 
rodrigoantunes profile image
Rodrigo Antunes

I think you want to animate the element when open/close, right?
I didn't try that yet. Although I found a blog post on dealing with this animated element, here: css-tricks.com/how-to-animate-the-...
It uses the Web Animation API insted of View Transition API, but maybe is this the effect you are looking for, and it will work in all browsers, hope it helps

Thread Thread
 
rodrigoantunes profile image
Rodrigo Antunes