Portrait picture
Zacharias Enochsson
Web Developer
contact

Transition Group Web Component

Animating appearance, disappearance and layout shifts of elements in a DOM can be tricky. That's why many frameworks offer utilities to handle it for you. I offer you this standards-based web-component to use with any framework (or none)!

In this simple demo there is a list of numbers, with new numbers added at the bottom every 2 seconds. The list is capped to four numbers by removing the top one when new numbers are pushed on the bottom.

The code itself only manages the logic of updating and rendering the list. The animations are managed by the <transition-group> tag, by applying classes specfied in the entry=, exit= and slide= attributes.

view-component.jsx


import "webcomponent-transition-group"

export default ({strings}) => (
  <ul class="toasts">
    <transition-group
      entry="slide"
      exit="pop"
      slide="slide"
    >
      {strings.map(str => (
        <li class="toast" key={str}>
          {str}
        </li>
      ))}
    </transition-group>
  </ul>
)
      

transition-styles.css

   
.slide-pre {
  transform: translateY(200%);
  opacity: 0;
}

.pop {
  transform: scale(2, 2);
  opacity: 0;
}

.slide, .pop {
  transition: 0.4s;
}
      

Only specify the transitions you need

If you don't provide a transition-directive in the css for a specified transition-class, there will be errors.

In this example, only the slide transition is needed, so that's all we provide.

view-component.jsx


import 'webcomponent-transition-group'

export default ({ordering, images, Move}) => (
  <transition-group slide="slide" class="board">
    {ordering.map(index => (
      <img
        src={images[index]}
        class={{
          blank: !index,
          square: !!index
        }}
        onclick={[Move, index]}
      />
    )}  
  </transition-group>
)

      

transition-styles.jsx


.slide { transition: 0.2s; }
.board {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  grid-template-rows: 1fr 1fr 1fr 1fr;
}
      

Dynamic transitions

The transition classes to use are read at the moment each transition begins. That means you can change the classes to get different transitions.

Like in this example, where the transitions can go to the left or right depending on which control you click, and which slide is currently displayed


import 'webcomponent-transition-group';

export default ({slides, current, direction}) => (
  <div class="screen">
    <transition-group
      entry={"slide-entry-" + direction}
      exit={"slide-exit-" + direction}
    >
      <Slide key={"slide" + current}>
        {slides[current]}
      </Slide>
    </transition-group> 
  </div>
)
      

.slide-entry-left-pre,
.slide-exit-right {
  transform: translateX(-100%);
  opacity: 0;
}
.slide-exit-left,
.slide-entry-right-pre {
  transform: translateX(100%);
  opacity: 0;
}
.slide-entry-left,
.slide-exit-left,
.slide-entry-right,
.slide-exit-right {
  transition: 0.8s;
}
  
      

Like what you've seen? Feel like giving it a go yourself? Bring the <transition-group> tag in to your project, either with a script tag in your html:

<script type="module" src="https://unpkg.com/webcomponent-transition-group"></script>

...or by npm install webcomponent-transition-group and then import "webcomponent-transition-group" in every component that uses the <transition-group> tag

Check the code, report bugs and issues, at GitHub.