Subscribe on changes!

Measurement Anchor Mode for <transition-group>

avatar
Jan 30th 2021

What problem does this feature solve?

Currently, <transition-group>s measure the position of the element from the top left of its bounding box. This works well for purely left-to-right and top-to-bottom situations. However, in some cases, children may change in ways that suggest they are anchored at the bottom or right of their bounding box. This can cause the element to appear to unintuitively jerk up before transitioning again to the correct position.

One example (my use case) is a chat-style application where an item within the chat message list has a part that is hidden after a certain amount of time. In my case, scrolling in the list starts from the bottom. I want the older messages in the list to transition downward to close the now vacant space without causing the changed element to jerk up first. Currently I see no easy workaround to enable me to use transition-group without this jerking. I may have to re-implement the FLIP animation myself, which feels bad.

Another use case is right-to-left text modes.

Currently, in the source code, left and top properties of ClientRect are hard coded. Adding an option to instead measure the delta from the right and bottom of the rect would be a simple change that would enable me use transition-group for my use case.

Codesandbox showing actual and desired behavior: https://codesandbox.io/s/transition-group-bottom-anchored-example-nv3bh?file=/src/App.vue

What does the proposed API look like?

Add an anchor prop, where the options are:

anchor = "top" | "top-right" | "right" | "bottom-right" | "bottom" | "bottom-left" | "left" | "top-left" where each implies measuring from that corner or midpoint.

Or, more simply:

anchor = "start" | "end" where "start" means "measure from the top left" and "end" means "measure from the bottom right"

Example:

<transition-group tag="ul" name="transition-name" anchor="end" class="list">
    <li class="list-item" v-for="item in items" :key="item.key">{{ item.text }}</li>
</transition-group>

In this example, .list-items appear to have a "downward gravity," so when a .list-item changes in height, the items above it will move down, but the .list-item's bottom edge will not have moved.

avatar
Jan 31st 2021

For the moment, I'm working around the problem by "cloning-and-owning" the source code for TransitionGroup. Simply changing top to bottom; and left to right does exactly what I needed it to do.

avatar
Jan 31st 2021

do you have a boiled down repro to illustrate the bug? Are you changing the origin of the translation after the element is added?

avatar
Jan 31st 2021

This has to do with the reference point on the measured ClientRect used to calculate the translation delta between the start and end states of the F.L.I.P. animation. Measuring from the top-left is not appropriate for lists whose "gravity" tends to the right or downward, such as in chat applications or horizontal lists in rtl languages.

The problem is subtle, but when you notice it, it's quite annoying.

I created this codesandbox to show the actual and desired behavior: https://codesandbox.io/s/transition-group-bottom-anchored-example-nv3bh?file=/src/App.vue

avatar
Feb 1st 2021

Oh, so you are changing the size of an element inside of the transition-group and you want it to stay where it was independently of what changed inside?

Thanks for the clear reproduction with the actual desired behavior 🙌

I'm not sure if this should and could work out of the box, otherwise, the idea of adding a new prop seems alright, it should probably go through an RFC for naming and edge cases

avatar
Feb 2nd 2021

@posva Should we need to close this one and put it in the RFC for discussion?

avatar
Feb 2nd 2021

I think this one is worth having open because it really shows a case that can be improved and how to implement it, but that's my just opinion.

@eli-crow do you feel like opening an RFC at https://github.com/vuejs/rfcs? You seem to have a lot of content already, the idea would be to be more problem-centric to make sure the proposed api can solve all the edge cases as well

avatar
Feb 2nd 2021

@posva Exactly. But defining "stay where it was" is dependent on which direction gravity is pointing.

I'll see if I have some time to submit an RFC this week.

avatar
Feb 4th 2021

Submitted my first RFC here: https://github.com/vuejs/rfcs/pull/262 Feel free to close this issue.

avatar
Feb 4th 2021

@eli-crow Great thanks, then I close this one.