Motion makes it simple to animate an element's size and position between different layouts. With animateLayout and the data-layout prop, you can perform layout animations, and by using data-layout-id you can create seamless "magic motion" effects between two separate elements.
Layout animations can animate previously unanimatable CSS values, like switching justify-content between flex-start and flex-end.
animateLayout(()=>{element.style.justifyContent = isOn ? "flex-start" : "flex-end"})
animateLayout(()=>{element.style.justifyContent = isOn ? "flex-start" : "flex-end"})
animateLayout(()=>{element.style.justifyContent = isOn ? "flex-start" : "flex-end"})
We can scope layout animations to a specific part of a page by passing a selector or element(s) as the first argument:
// Either as a selectoranimateLayout(".container",update)// Or an element/element listconstcontainer = document.getElementById("#container")animateLayout(container,update)
// Either as a selectoranimateLayout(".container",update)// Or an element/element listconstcontainer = document.getElementById("#container")animateLayout(container,update)
// Either as a selectoranimateLayout(".container",update)// Or an element/element listconstcontainer = document.getElementById("#container")animateLayout(container,update)
It's possible to animate from one element to another different element by removing an existing element and then adding a new element to the DOM with matching data-layout-id attributes:
<ulclass="tabs"><li>
First
<divdata-layout-id="underline"class="underline"></div></li><li>Second</li><li>Third</li></ul>
<ulclass="tabs"><li>
First
<divdata-layout-id="underline"class="underline"></div></li><li>Second</li><li>Third</li></ul>
<ulclass="tabs"><li>
First
<divdata-layout-id="underline"class="underline"></div></li><li>Second</li><li>Third</li></ul>
constfirstItem = document.querySelector(".tabs li:first-child")constunderline = firstItem.querySelector("[data-layout-id='underline']")underline.remove()// Add underline to second itemconstsecondItem = document.querySelector(".tabs li:nth-child(2)")constnewUnderline = document.createElement("div")newUnderline.setAttribute("data-layout-id","underline")newUnderline.className = "underline"secondItem.appendChild(newUnderline)
constfirstItem = document.querySelector(".tabs li:first-child")constunderline = firstItem.querySelector("[data-layout-id='underline']")underline.remove()// Add underline to second itemconstsecondItem = document.querySelector(".tabs li:nth-child(2)")constnewUnderline = document.createElement("div")newUnderline.setAttribute("data-layout-id","underline")newUnderline.className = "underline"secondItem.appendChild(newUnderline)
constfirstItem = document.querySelector(".tabs li:first-child")constunderline = firstItem.querySelector("[data-layout-id='underline']")underline.remove()// Add underline to second itemconstsecondItem = document.querySelector(".tabs li:nth-child(2)")constnewUnderline = document.createElement("div")newUnderline.setAttribute("data-layout-id","underline")newUnderline.className = "underline"secondItem.appendChild(newUnderline)
In the React version of layout animations, we can also crossfade back to the original element by removing the new element using <AnimatePresence>. As there is not yet an <AnimatePresence> equivalent for vanilla JS, this is not yet possible.
Unlock the full vault of 330+ Motion examples, 100+ tutorials, premium APIs, private Discord and GitHub, and powerful Motion Studio animation editing tools for your IDE.