Shared-Element Transitions (data-vt-shared)
Slide transitions move entire screens. Shared-element transitions morph a specific element from its old position to its new one using a FLIP (First, Last, Invert, Play) overlay — similar to native mobile navigation.
Mark elements with data-vt-shared="key". When transitionId changes inside an auto-transition host, Dim finds matching keys in the outgoing and incoming DOM trees and animates between them.
Basic usage
return html`
<div class="feature-card" data-vt-shared="hero-card">
<h3>${title}</h3>
<p>${description}</p>
</div>
`;
Use the same key on both the outgoing and incoming views. Only one element per key should exist in each layer at a time.
Naming convention with sharedKeys
Product and messaging demos use a helper to avoid key collisions:
export const sharedKeys = (id) => ({
image: `image-${id}`,
name: `name-${id}`,
price: `price-${id}`,
category: `category-${id}`,
});
// In a product card:
const keys = sharedKeys(product.id);
return html`
<img data-vt-shared="${keys.image}" src="${product.image}" alt="" />
<span data-vt-shared="${keys.name}">${product.name}</span>
<span data-vt-shared="${keys.price}">$${product.price}</span>
`;
The detail screen reuses the same sharedKeys(product.id) so the image and title morph from list → detail.
Where transitions apply
Shared-element FLIP runs when:
- The component has an active
transitionId(auto transition host) - Both outgoing and incoming trees contain a matching
data-vt-sharedvalue - The transition host has finished measuring both layers
Shared elements do not morph when:
- Content is in an overlay/drawer that sits outside the transition host
- Keys differ between old and new views
transitionIdis unchanged
Keep navigation content inside the transitioning host; open modals and drawers as siblings that do not participate in the slide.
Combining slides and shared elements
Typical app structure:
const viewId = computeViewId(activeTab, navStack);
return html`
<navigation-view transitionId="${viewId}" .props=${{ navStack, activeTab }}>
<!-- tab bar with data-vt-shared on icons that persist across tabs -->
</navigation-view>
`;
The shopping and messaging demos in the Dim Storybook are the reference implementations:
- Shopping — product image, name, price morph from catalog → product detail
- Messaging — conversation avatar and title morph from list → chat header
Implementation notes
AutoTransitionHost (internal to define()):
- Captures bounding rects of shared elements in outgoing and incoming layers
- Creates a fixed-position overlay clone
- Animates
transformfrom First → Last position over the transition duration - Removes the overlay when the slide completes
You do not call FLIP APIs directly — only mark up with data-vt-shared.
Debugging tips
- Element jumps instead of morphing — keys mismatch or duplicate keys in one layer
- No morph, slide only — element missing
data-vt-sharedon one side - Collapsed animation — host not block-level; ensure parent has height (see View Transitions guide)
Conclusion
data-vt-shared turns Dim’s slide transitions into app-quality navigation. Pair consistent key helpers with a stable transitionId strategy from your nav stack.