Smooth, native animations for content swaps using the View Transitions API.
Enabling Transitions
View Transitions are enabled by default. To explicitly control them:
<!-- Enable globally --><html data-transitions> <!-- Disable for specific section --><div data-transitions="false"> ...</div> <!-- Via meta tag --><meta name="htmlstar:transitions" content="true">
How It Works
When a swap occurs and View Transitions are enabled:
- html★ calls
document.startViewTransition() - Browser captures a screenshot of the old state
- Content is swapped
- Browser captures the new state
- CSS animations run between the two states
CSS for Transitions
Use view-transition-name to identify elements that should animate:
/* Give the element a transition name */#main { view-transition-name: main-content;} /* Animate the old state (exiting) */::view-transition-old(main-content) { animation: fade-out 0.2s ease-out;} /* Animate the new state (entering) */::view-transition-new(main-content) { animation: fade-in 0.2s ease-in;} @keyframes fade-out { to { opacity: 0; }} @keyframes fade-in { from { opacity: 0; }}
Animation Examples
Slide
::view-transition-old(content) { animation: slide-out 0.2s ease-out;} ::view-transition-new(content) { animation: slide-in 0.2s ease-in;} @keyframes slide-out { to { opacity: 0; transform: translateX(-20px); }} @keyframes slide-in { from { opacity: 0; transform: translateX(20px); }}
Scale
::view-transition-old(content) { animation: scale-out 0.15s ease-out;} ::view-transition-new(content) { animation: scale-in 0.15s ease-in;} @keyframes scale-out { to { opacity: 0; transform: scale(0.95); }} @keyframes scale-in { from { opacity: 0; transform: scale(1.05); }}
Crossfade (Simple)
::view-transition-old(content),::view-transition-new(content) { animation-duration: 0.2s;} /* Default crossfade is built-in! */
Multiple Elements
Different elements can have different transitions:
header { view-transition-name: header; }main { view-transition-name: main; }aside { view-transition-name: sidebar; } /* Header stays put */::view-transition-old(header),::view-transition-new(header) { animation: none;} /* Main content slides */::view-transition-old(main) { animation: slide-left-out 0.2s;} ::view-transition-new(main) { animation: slide-left-in 0.2s;}
CSS Transitions Fallback
When the View Transitions API is unavailable, html★ automatically falls back to CSS class-based transitions. No configuration needed — it just works.
How the Fallback Works
.htmlstar-swappingis added to the target element (triggers fade-out)- html★ waits for the CSS transition to complete
- Content is swapped
.htmlstar-swappingis removed,.htmlstar-settlingis added (triggers fade-in)- html★ waits for the settle transition
.htmlstar-settlingis removed
Default Styles
html★ injects default fallback styles automatically:
/* Injected by html★ */.htmlstar-swapping { opacity: 0; transition: opacity 150ms ease-out;}.htmlstar-settling { opacity: 1; transition: opacity 150ms ease-in;}
Custom Fallback Animations
Override the defaults in your own CSS for custom fallback effects:
/* Slide down instead of fade */.htmlstar-swapping { opacity: 0; transform: translateY(-10px); transition: opacity 200ms ease-out, transform 200ms ease-out;}.htmlstar-settling { opacity: 1; transform: translateY(0); transition: opacity 200ms ease-in, transform 200ms ease-in;}
The fallback ensures graceful transitions in all browsers, while browsers with View Transitions API support get the full native experience.
Browser Support
| Browser | View Transitions API | CSS Fallback |
|---|---|---|
| Chrome | 111+ | ✓ |
| Edge | 111+ | ✓ |
| Safari | 18+ | ✓ |
| Firefox | 133+ | ✓ |
Graceful Degradation: All modern browsers now support the native View Transitions API. In older browsers, html★ automatically uses the CSS class-based fallback described above — smooth transitions everywhere, no errors, no broken layouts.
Disabling for Specific Swaps
<!-- This swap won't animate --><button data-href="/api/save" data-target="#status" data-transitions="false"> Save</button>