Skip to main content Skip to docs navigation

Modal Navigation

Stack-based navigation inside modals with automatic back buttons, smooth animations, and declarative wiring via rel attributes.

Build multi-step workflows without z-index nightmares. One modal shell, multiple screens, proper navigation.

Basic usage

Simple navigation

import { Modal, ModalNavigation } from '@appitude/bravo';

// Create a navigation instance
const nav = new ModalNavigation();

// Create a modal
const welcome = new Modal({
  title: 'Welcome',
  content: '<p>Hello from modal navigation!</p>'
});

// Push the modal to navigation and show
nav.push(welcome);
nav.show();

Using existing modals

// If you already have a modal in the DOM
const existingModal = new Modal('#my-existing-modal');

const nav = new ModalNavigation();
nav.push(existingModal);
nav.show();

Building a navigation flow

const nav = new ModalNavigation();

// First screen with a button to navigate forward
const first = new Modal({
  title: 'Step 1',
  content: `
    <p>This is the first screen.</p>
    <button rel="step-2" class="btn btn-primary">Continue</button>
  `
});

// Second screen with ID that matches the rel attribute
const second = new Modal({
  id: 'step-2',
  title: 'Step 2',
  content: `
    <p>You made it to step 2!</p>
    <button rel="back" class="btn btn-secondary">Go Back</button>
    <button rel="close" class="btn btn-success">Done</button>
  `
});

// Start the navigation
nav.push(first);
nav.show();

Advanced navigation

Push/pop navigation

const nav = new ModalNavigation();

nav.push(firstModal);   // Add to stack and navigate forward
nav.show();             // Open the navigation
nav.push(secondModal);  // Navigate to next screen
nav.pop();              // Go back one screen
nav.close();            // Close entire navigation

Using rel attributes

Any element with a rel attribute becomes a navigation trigger:

<button rel="settings">Settings</button>   <!-- Navigate to #settings modal -->
<button rel="back">โ† Back</button>        <!-- Go to previous screen -->
<button rel="close">Cancel</button>        <!-- Close entire navigation -->

When clicked, the navigation:

  1. First checks if a modal with that ID was already pushed (reuses from cache)
  2. Otherwise looks for an existing Modal instance with that ID
  3. If neither found, looks for an existing modal element in the DOM and creates a Modal instance from it
  4. Pushes the modal onto the navigation stack

Controlling the back button

The back button automatically appears when stack depth > 1. You can disable it for specific modals:

const finalStep = new Modal({
  title: 'Complete',
  backButton: { disabled: true },  // No going back from here
  content: '<p>This is the final screen.</p>'
});

See the shopping demo above where the order confirmation prevents going back after purchase.

Transition animations

Choose between two animation styles when navigating between screens:

// Slide animation (default) - iOS-style horizontal slide
const slideNav = new ModalNavigation({
  animation: 'slide'
});

// Morph animation - Smooth size morphing between screens
const morphNav = new ModalNavigation({
  animation: 'morph'
});

The slide animation provides iOS-style navigation with horizontal movement. The morph animation smoothly resizes the modal between different content sizes.

Configuration & Events

Configuration

new ModalNavigation({
  animation: 'slide',     // Animation type: 'slide' or 'morph'
  backButton: {
    disabled: false,      // Show/hide back button
    text: ''              // Custom back button text/icon
  },
  closeButton: {
    disabled: false,      // Show/hide close button
    text: ''              // Custom close button text/icon
  }
});

Events

// Navigation lifecycle
document.addEventListener('open.bs.nav', handler);      // Navigation opening
document.addEventListener('opened.bs.nav', handler);    // Navigation opened
document.addEventListener('close.bs.nav', handler);     // Navigation closing

// Navigation movement
document.addEventListener('forward.bs.nav', handler);   // Starting forward navigation
document.addEventListener('forwarding.bs.nav', handler); // Animation in progress
document.addEventListener('forwarded.bs.nav', handler);  // Forward complete

document.addEventListener('back.bs.nav', handler);      // Starting back navigation
document.addEventListener('backing.bs.nav', handler);    // Animation in progress
document.addEventListener('backed.bs.nav', handler);     // Back complete

All events include e.detail.stack with the current navigation stack.

Key features

  • Navigation stack โ€” Push/pop screens instead of stacking multiple modals
  • Automatic back button โ€” Appears when needed (stack > 1), no manual wiring
  • Smooth transitions โ€” Slide or morph animations between screens
  • Declarative navigation โ€” Use rel attributes to wire up navigation
  • Modal reuse โ€” Previously shown modals are cached and reused
  • Single backdrop โ€” No z-index issues or backdrop flashing
  • CSS hooks โ€” .modal-navigation and .modal-navigation-stacked classes for custom styling