Skip to main content

View Transitions with useViewTransition

Dim includes a view transition system for sliding between UI states. The exported hook is useViewTransition (Storybook may label the section useTransition() — they refer to the same API).

There are two ways to use transitions:

  1. Declarative (auto) — set a transitionId prop on a component; Dim wraps the render in a two-layer slide host automatically.
  2. Imperative (manual) — call useViewTransition() inside your component for full control.

Declarative auto transitions

When a component receives a transitionId (via attribute or .props), Dim detects it during render and applies slide transitions whenever the id changes:

import { define, html, css, useState, useStyle } from "../core/dim.ts";

const PageHost = (props, { useState, useStyle, html, css }) => {
const [pageIndex, setPageIndex] = useState(0);

useStyle(css`
.page { padding: 1rem; min-height: 200px; }
.nav { display: flex; gap: 0.5rem; margin-bottom: 1rem; }
`);

return html`
<div>
<nav class="nav">
<button @click="${() => setPageIndex(0)}">Home</button>
<button @click="${() => setPageIndex(1)}">About</button>
<button @click="${() => setPageIndex(2)}">Contact</button>
</nav>
<page-content
transitionId="${pageIndex}"
transitionDuration="400"
.props=${{ pageIndex }}
></page-content>
</div>
`;
};

const PageContent = (props, { html }) => {
const titles = ["Home", "About", "Contact"];
return html`<div class="page"><h2>${titles[props.pageIndex]}</h2></div>`;
};

define({ tag: "page-host", component: PageHost });
define({ tag: "page-content", component: PageContent });

Auto transition props

PropDescription
transitionIdAny string or number; changes trigger a slide
transitionDurationDuration in ms (default 500)
transitionAutoDirection"false" disables numeric direction detection

Direction is inferred automatically: higher numeric ids slide from the right, lower from the left.


Manual useViewTransition

For galleries, wizards, or custom animation logic, call the hook directly:

import {
define,
html,
css,
useState,
useStyle,
useViewTransition,
viewTransitionStyles,
} from "../core/dim.ts";

const Gallery = (props, { useState, useStyle, useViewTransition, html, css }) => {
const [index, setIndex] = useState(0);
const transition = useViewTransition(index.toString(), {
duration: 400,
autoDirection: true,
});

useStyle(css`
${viewTransitionStyles}
.slide-container { position: relative; overflow: hidden; }
.slide { padding: 2rem; }
`);

const goNext = () => {
if (!transition.isTransitioning) {
setIndex((i) => i + 1);
}
};

return html`
<div class="slide-container">
<div class="${transition.getIncomingClass('slide')}">
<h2>Slide ${index}</h2>
<button @click="${goNext}">Next</button>
</div>
</div>
`;
};

define({ tag: "my-gallery", component: Gallery });

Hook return value

Property / methodPurpose
isTransitioningWhether a transition is in progress
direction'left' or 'right'
currentId / previousIdLast and previous transition ids
startTransition(id, direction?)Imperatively start a transition
endTransition()End the current transition early
getIncomingClass(base?)CSS class for incoming layer
getOutgoingClass(base?)CSS class for outgoing layer
getTransitionStyles()Inline style object for duration/easing
optionsResolved options object

Import viewTransitionStyles and inject it with useStyle to get the base slide CSS (.slide-in-right, .slide-out-left, etc.).


Two-layer rendering

Auto mode uses AutoTransitionHost internally:

  • Incoming layer — current content slides in
  • Outgoing layer — previous content slides out in the opposite direction
  • Wrapper height animation — container height animates to match new content

Custom elements default to display: inline; transition hosts force block layout so layers are visible. If slides appear invisible, check that the host has block display and non-zero height.


Multi-screen apps combine transitionId with a navigation stack. See 10. Building a Multi-Screen App and 7. Shared-Element Transitions for FLIP animations on top of slides.

Live examples: Dim Storybook — View Transitions.


Conclusion

useViewTransition and auto transitionId give Dim a distinctive navigation story without a separate router package. Use declarative ids for page hosts and the manual hook when you need fine-grained control over timing and CSS classes.