A lightweight TypeScript library for managing DOM history with smooth transitions and view chaining. Build beautiful, animated navigation experiences with zero dependencies.
- π― Simple API - Intuitive methods for view management
- π¨ Smooth Transitions - Built-in fade, slide, and scale effects
- π Custom Transitions - Easy registration of custom transition effects
- π Lifecycle Hooks - Control view behavior with lifecycle methods
- π± Web Components - Standard Custom Elements API
- π Back Button - Built-in navigation with customizable appearance
- πͺΆ Lightweight - Pure TypeScript with zero dependencies
- πͺ View Chaining - Multiple stack views working together
- ποΈ Configurable - Attributes and properties for easy customization
npm install stackview.ts<stack-view id="myStack" effect="slide"></stack-view>
<script type="module">
import StackView from './dist/stackview.js';
const stackView = document.getElementById('myStack');
// Create a view
const view = document.createElement('div');
view.innerHTML = '<h1>Hello World!</h1>';
// Show it with animation
await stackView.begin(view);
// Go back
await stackView.complete();
</script>import StackView from 'stackview.ts';
const stackView = document.getElementById('myStack') as StackView;
// Create and show a view
const view = document.createElement('div');
view.innerHTML = '<h1>Welcome!</h1>';
await stackView.begin(view, 'fade', { duration: 500 });
// Navigate back
await stackView.complete();Get or set the default transition effect.
stackView.effect = "slide"; // Set via JavaScript<stack-view effect="fade"></stack-view> <!-- Set via HTML -->Available effects: fade, slide, scale (or custom registered effects)
Show or hide the back/close button.
stackView.backButton = false; // Hide button<stack-view back-button="false"></stack-view>Customize the back button text.
stackView.backButtonText = "β Back";<stack-view back-button-text="βΉ Back"></stack-view>Customize the close button text (shown when no history).
stackView.closeButtonText = "β Close";<stack-view close-button-text="Γ Close"></stack-view>Show a new view with optional transition effect.
await stackView.begin(element);
await stackView.begin(element, 'slide');
await stackView.begin(element, 'fade', { duration: 600, easing: 'ease-in-out' });Parameters:
element: HTMLElement- The view element to showeffectKey?: string- Transition effect key (optional)transition?: Partial<ViewTransition>- Transition settings (optional)
Go back to the previous view or close if no history.
await stackView.complete();Check if there are previous views in history.
if (stackView.canGoBack()) {
await stackView.complete();
}Get the currently visible view element.
const currentView = stackView.getCurrentView();Get the view history array.
const history = stackView.getHistory();
console.log(`${history.length} views in history`);Go back multiple steps in history.
await stackView.goBack(2); // Go back 2 viewsClear all view history.
stackView.clearHistory();Remove a specific view from the stack.
await stackView.terminateView(someElement);Set default transition settings for all views.
stackView.setDefaultTransition({
duration: 400,
easing: 'cubic-bezier(0.4, 0, 0.2, 1)'
});Register a custom transition effect.
StackView.registerTransition('flip', {
enter: (element) => {
element.style.transform = 'rotateY(90deg)';
element.style.opacity = '0';
},
exit: (element) => {
element.style.transform = 'rotateY(-90deg)';
element.style.opacity = '0';
},
cleanup: (element) => {
element.style.transform = '';
element.style.opacity = '';
}
});
// Use it
await stackView.begin(view, 'flip');Implement these optional methods on your view elements to hook into the lifecycle:
class MyView extends HTMLElement {
async stackViewShowing(stackView: StackView): Promise<void> {
console.log('View is about to be shown');
// Initialize data, setup listeners, etc.
}
async stackViewHiding(stackView: StackView): Promise<void> {
console.log('View is about to be hidden');
// Validate data, confirm navigation, etc.
}
async stackViewHidden(stackView: StackView): Promise<void> {
console.log('View has been hidden');
// Cleanup resources, save state, etc.
}
}Smooth opacity transition.
await stackView.begin(view, 'fade');Horizontal slide animation.
await stackView.begin(view, 'slide');Scale with opacity animation.
await stackView.begin(view, 'scale');const view1 = document.createElement('div');
view1.innerHTML = '<h1>First View</h1>';
await stackView.begin(view1);
const view2 = document.createElement('div');
view2.innerHTML = '<h1>Second View</h1>';
await stackView.begin(view2, 'slide');
// Go back
await stackView.complete(); // Returns to view1await stackView.begin(view, 'fade', {
duration: 800,
easing: 'ease-in-out'
});// Navigate forward multiple times
await stackView.begin(step1View);
await stackView.begin(step2View);
await stackView.begin(step3View);
// Go back 2 steps
await stackView.goBack(2);class ProfileView extends HTMLElement {
async stackViewShowing(stackView: StackView): Promise<void> {
// Load user data
const userData = await fetch('/api/user').then(r => r.json());
this.innerHTML = `<h1>${userData.name}</h1>`;
}
async stackViewHidden(stackView: StackView): Promise<void> {
// Save changes
await this.saveProfile();
}
}
customElements.define('profile-view', ProfileView);
const profile = document.createElement('profile-view');
await stackView.begin(profile);<stack-view
effect="slide"
back-button="true"
back-button-text="β¬
Back"
close-button-text="β">
</stack-view>stackView.effect = "scale";
stackView.backButton = false; // Hide button
stackView.backButtonText = "β Previous";// Register a custom bounce effect
StackView.registerTransition('bounce', {
enter: (element) => {
element.style.transform = 'scale(0.3)';
element.style.opacity = '0';
},
exit: (element) => {
element.style.transform = 'scale(1.5)';
element.style.opacity = '0';
},
cleanup: (element) => {
element.style.transform = '';
element.style.opacity = '';
}
});
// Use with custom timing
await stackView.begin(view, 'bounce', {
duration: 600,
easing: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)'
});// Create multiple stack views that work together
const mainStack = document.getElementById('mainStack') as StackView;
const modalStack = document.getElementById('modalStack') as StackView;
// Show main content
await mainStack.begin(homeView);
// Show modal on top
await modalStack.begin(settingsView);The component automatically adds minimal default styles (display: block). You can override with CSS:
stack-view {
width: 100%;
height: 100vh;
background: #f5f5f5;
border-radius: 8px;
}
.stackview-item {
padding: 20px;
}
.stackview-back-button {
background: #3498db;
color: white;
font-size: 18px;
}Full TypeScript support with type definitions included:
import StackView, {
ViewTransition,
TransitionEffect,
ViewHistoryItem
} from 'stackview.ts';
// Type-safe API
const stackView: StackView = document.getElementById('stack') as StackView;
// Custom transition with types
const customEffect: TransitionEffect = {
enter: (element: HTMLElement) => { /* ... */ },
exit: (element: HTMLElement) => { /* ... */ },
cleanup: (element: HTMLElement) => { /* ... */ }
};
StackView.registerTransition('custom', customEffect);- Chrome/Edge 80+
- Firefox 75+
- Safari 13+
- Modern browsers with Custom Elements support
MIT Β© Xoboto
Contributions are welcome! Please feel free to submit a Pull Request.
- π Report Issues
- π¬ Discussions
Give a βοΈ if this project helped you!
Made with β€οΈ by Xoboto