| <!doctype html> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1"> |
| <link href="../../../dist/css/bootstrap.min.css" rel="stylesheet"> |
| <title>Menu Submenus</title> |
| <style> |
| .test-section { |
| padding: 2rem 0; |
| border-bottom: 1px solid var(--border-color); |
| } |
| .test-section:last-child { |
| border-bottom: 0; |
| } |
| .demo-box { |
| min-height: 300px; |
| display: flex; |
| align-items: flex-start; |
| gap: 1rem; |
| flex-wrap: wrap; |
| } |
| .demo-box-center { |
| align-items: center; |
| justify-content: center; |
| } |
| .feature-list { |
| font-size: 0.875rem; |
| color: var(--fg-2); |
| } |
| .feature-list li { |
| margin-bottom: 0.25rem; |
| } |
| .keyboard-hint { |
| display: inline-block; |
| padding: 0.125rem 0.375rem; |
| font-size: 0.75rem; |
| font-family: ui-monospace, monospace; |
| background: var(--bg-2); |
| border-radius: var(--border-radius); |
| border: 1px solid var(--border-color); |
| } |
| </style> |
| </head> |
| <body> |
| <div class="container py-4"> |
| <h1 class="mb-4">Menu Submenus <small class="fg-2">Bootstrap Visual Test</small></h1> |
| |
| <div class="alert theme-info"> |
| <strong>Keyboard Navigation:</strong> |
| <span class="keyboard-hint">↓</span> <span class="keyboard-hint">↑</span> navigate items, |
| <span class="keyboard-hint">→</span> enter submenu, |
| <span class="keyboard-hint">←</span> exit submenu, |
| <span class="keyboard-hint">Enter</span> or <span class="keyboard-hint">Space</span> activate, |
| <span class="keyboard-hint">Esc</span> close, |
| <span class="keyboard-hint">Home</span> <span class="keyboard-hint">End</span> jump to first/last |
| </div> |
| |
| <!-- Basic Submenu --> |
| <section class="test-section"> |
| <h2>Basic Submenu</h2> |
| <p class="fg-2">Single level submenu with hover and click activation.</p> |
| |
| <div class="demo-box"> |
| <div> |
| <button class="btn-solid theme-primary" type="button" data-bs-toggle="menu" aria-expanded="false"> |
| Menu with Submenu |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Action</a> |
| <a class="menu-item" href="#">Another action</a> |
| <hr class="menu-divider"> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| More options |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Sub-action 1</a> |
| <a class="menu-item" href="#">Sub-action 2</a> |
| <a class="menu-item" href="#">Sub-action 3</a> |
| </div> |
| </div> |
| <a class="menu-item" href="#">Something else</a> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| <!-- Nested Submenus --> |
| <section class="test-section"> |
| <h2>Nested Submenus (Multi-level)</h2> |
| <p class="fg-2">Three levels of nested submenus.</p> |
| |
| <div class="demo-box"> |
| <div> |
| <button class="btn-solid theme-secondary" type="button" data-bs-toggle="menu" aria-expanded="false"> |
| Multi-level Menu |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Level 1 - Action</a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Level 1 - Submenu |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Level 2 - Action</a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Level 2 - Submenu |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Level 3 - Action A</a> |
| <a class="menu-item" href="#">Level 3 - Action B</a> |
| <a class="menu-item" href="#">Level 3 - Action C</a> |
| </div> |
| </div> |
| <a class="menu-item" href="#">Level 2 - Another</a> |
| </div> |
| </div> |
| <a class="menu-item" href="#">Level 1 - Another</a> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| <!-- Multiple Submenus --> |
| <section class="test-section"> |
| <h2>Multiple Submenus at Same Level</h2> |
| <p class="fg-2">Multiple submenu triggers in the same menu - opening one closes the other.</p> |
| |
| <div class="demo-box"> |
| <div> |
| <button class="btn-solid theme-info" type="button" data-bs-toggle="menu" aria-expanded="false"> |
| Multiple Submenus |
| </button> |
| <div class="menu"> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| File operations |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">New</a> |
| <a class="menu-item" href="#">Open</a> |
| <a class="menu-item" href="#">Save</a> |
| <a class="menu-item" href="#">Save As...</a> |
| </div> |
| </div> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Edit operations |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Cut</a> |
| <a class="menu-item" href="#">Copy</a> |
| <a class="menu-item" href="#">Paste</a> |
| </div> |
| </div> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| View options |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Zoom In</a> |
| <a class="menu-item" href="#">Zoom Out</a> |
| <a class="menu-item" href="#">Fit to Window</a> |
| </div> |
| </div> |
| <hr class="menu-divider"> |
| <a class="menu-item" href="#">Preferences</a> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| <!-- Viewport Flipping Test --> |
| <section class="test-section"> |
| <h2>Viewport Detection (Flipping)</h2> |
| <p class="fg-2">Submenus flip to the opposite side when there's not enough space. Try the one on the right.</p> |
| |
| <div class="demo-box" style="justify-content: space-between;"> |
| <div> |
| <button class="btn-solid theme-success" type="button" data-bs-toggle="menu" aria-expanded="false"> |
| Left Side (opens right) |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Action</a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Submenu |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Sub-action 1</a> |
| <a class="menu-item" href="#">Sub-action 2</a> |
| </div> |
| </div> |
| </div> |
| </div> |
| |
| <div> |
| <button class="btn-solid theme-success" type="button" data-bs-toggle="menu" aria-expanded="false"> |
| Right Side (flips left) |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Action</a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Submenu (should flip) |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Sub-action 1</a> |
| <a class="menu-item" href="#">Sub-action 2</a> |
| <a class="menu-item" href="#">Sub-action 3</a> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| <!-- Navbar Integration --> |
| <section class="test-section"> |
| <h2>Navbar Integration</h2> |
| <p class="fg-2">Submenus work within navbar menus.</p> |
| |
| <nav class="navbar lg:navbar-expand bg-body-tertiary rounded"> |
| <div class="container-fluid"> |
| <a class="navbar-brand" href="#">Navbar</a> |
| <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSubmenu" aria-controls="navbarSubmenu" aria-expanded="false" aria-label="Toggle navigation"> |
| <span class="navbar-toggler-icon"></span> |
| </button> |
| <div class="collapse navbar-collapse" id="navbarSubmenu"> |
| <ul class="navbar-nav me-auto mb-2 mb-lg-0"> |
| <li class="nav-item"> |
| <a class="nav-link active" aria-current="page" href="#">Home</a> |
| </li> |
| <li class="nav-item"> |
| <a class="nav-link" href="#" role="button" data-bs-toggle="menu" aria-expanded="false"> |
| Products |
| </a> |
| <div class="menu"> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Electronics |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Phones</a> |
| <a class="menu-item" href="#">Laptops</a> |
| <a class="menu-item" href="#">Tablets</a> |
| </div> |
| </div> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Clothing |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Men's</a> |
| <a class="menu-item" href="#">Women's</a> |
| <a class="menu-item" href="#">Kids</a> |
| </div> |
| </div> |
| <hr class="menu-divider"> |
| <a class="menu-item" href="#">All Products</a> |
| </div> |
| </li> |
| <li class="nav-item"> |
| <a class="nav-link" href="#">About</a> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </nav> |
| </section> |
| |
| <!-- Dropup with Submenus --> |
| <section class="test-section"> |
| <h2>Dropup with Submenus</h2> |
| <p class="fg-2">Submenus work with dropup direction.</p> |
| |
| <div class="demo-box demo-box-center" style="min-height: 200px;"> |
| <div class="btn-group dropup"> |
| <button type="button" class="btn-solid theme-warning" data-bs-toggle="menu" aria-expanded="false"> |
| Dropup Menu |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Action</a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| More options |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Sub-action 1</a> |
| <a class="menu-item" href="#">Sub-action 2</a> |
| </div> |
| </div> |
| <a class="menu-item" href="#">Something else</a> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| <!-- With Icons --> |
| <section class="test-section"> |
| <h2>With Icons</h2> |
| <p class="fg-2">Submenus with icons in menu items.</p> |
| |
| <div class="demo-box"> |
| <div> |
| <button class="btn-solid theme-dark" type="button" data-bs-toggle="menu" aria-expanded="false"> |
| Menu with Icons |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> |
| <path d="M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71V3.5z"/> |
| <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm7-8A7 7 0 1 1 1 8a7 7 0 0 1 14 0z"/> |
| </svg> |
| Recent |
| </a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> |
| <path d="M1 3.5A1.5 1.5 0 0 1 2.5 2h2.764c.958 0 1.76.56 2.311 1.184C7.985 3.648 8.48 4 9 4h4.5A1.5 1.5 0 0 1 15 5.5v.64c.57.265.94.876.856 1.546l-.64 5.124A2.5 2.5 0 0 1 12.733 15H3.266a2.5 2.5 0 0 1-2.481-2.19l-.64-5.124A1.5 1.5 0 0 1 1 6.14V3.5zM2 6h12v-.5a.5.5 0 0 0-.5-.5H9c-.964 0-1.71-.629-2.174-1.154C6.374 3.334 5.82 3 5.264 3H2.5a.5.5 0 0 0-.5.5V6zm-.367 1a.5.5 0 0 0-.496.562l.64 5.124A1.5 1.5 0 0 0 3.266 14h9.468a1.5 1.5 0 0 0 1.489-1.314l.64-5.124A.5.5 0 0 0 14.367 7H1.633z"/> |
| </svg> |
| Folders |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Documents</a> |
| <a class="menu-item" href="#">Downloads</a> |
| <a class="menu-item" href="#">Pictures</a> |
| </div> |
| </div> |
| <hr class="menu-divider"> |
| <a class="menu-item" href="#"> |
| <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"> |
| <path d="M8 4.754a3.246 3.246 0 1 0 0 6.492 3.246 3.246 0 0 0 0-6.492zM5.754 8a2.246 2.246 0 1 1 4.492 0 2.246 2.246 0 0 1-4.492 0z"/> |
| <path d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 1-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 1-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 1 .52 1.255l-.16.292c-.892 1.64.901 3.434 2.541 2.54l.292-.159a.873.873 0 0 1 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 1 1.255-.52l.292.16c1.64.893 3.434-.902 2.54-2.541l-.159-.292a.873.873 0 0 1 .52-1.255l.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 1-.52-1.255l.16-.292c.893-1.64-.902-3.433-2.541-2.54l-.292.159a.873.873 0 0 1-1.255-.52l-.094-.319zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.415 1.6.42 1.184 1.185l-.159.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.319.094a1.873 1.873 0 0 0-1.115 2.693l.16.291c.415.764-.42 1.6-1.185 1.184l-.291-.159a1.873 1.873 0 0 0-2.693 1.116l-.094.318c-.246.835-1.428.835-1.674 0l-.094-.319a1.873 1.873 0 0 0-2.692-1.115l-.292.16c-.764.415-1.6-.42-1.184-1.185l.159-.291A1.873 1.873 0 0 0 1.945 8.93l-.319-.094c-.835-.246-.835-1.428 0-1.674l.319-.094A1.873 1.873 0 0 0 3.06 4.377l-.16-.292c-.415-.764.42-1.6 1.185-1.184l.292.159a1.873 1.873 0 0 0 2.692-1.115l.094-.319z"/> |
| </svg> |
| Settings |
| </a> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| <!-- Mobile Test --> |
| <section class="test-section"> |
| <h2>Mobile Mode</h2> |
| <p class="fg-2"> |
| Resize your browser to <768px width to see slide-over behavior. |
| On mobile, submenus slide in from the side with a back button. |
| </p> |
| |
| <div class="demo-box"> |
| <div> |
| <button class="btn-solid theme-danger" type="button" data-bs-toggle="menu" aria-expanded="false"> |
| Test on Mobile |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Action</a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Navigate to submenu |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Sub-action 1</a> |
| <a class="menu-item" href="#">Sub-action 2</a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Even deeper |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Deep action 1</a> |
| <a class="menu-item" href="#">Deep action 2</a> |
| </div> |
| </div> |
| </div> |
| </div> |
| <a class="menu-item" href="#">Something else</a> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| <!-- Disabled Items --> |
| <section class="test-section"> |
| <h2>With Disabled Items</h2> |
| <p class="fg-2">Keyboard navigation skips disabled items.</p> |
| |
| <div class="demo-box"> |
| <div> |
| <button class="btn-solid theme-outline-primary" type="button" data-bs-toggle="menu" aria-expanded="false"> |
| Menu with Disabled |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Enabled action</a> |
| <a class="menu-item disabled" href="#">Disabled action</a> |
| <div class="submenu"> |
| <button class="menu-item" type="button"> |
| Submenu |
| </button> |
| <div class="menu"> |
| <a class="menu-item" href="#">Enabled</a> |
| <a class="menu-item disabled" href="#">Disabled</a> |
| <a class="menu-item" href="#">Enabled</a> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </section> |
| |
| <!-- Feature Summary --> |
| <section class="test-section"> |
| <h2>Feature Summary</h2> |
| <div class="row"> |
| <div class="col-md-6"> |
| <h5>Mouse Interaction</h5> |
| <ul class="feature-list"> |
| <li>✅ Hover to open submenus</li> |
| <li>✅ Click to toggle submenus</li> |
| <li>✅ Safe triangle / hover intent (diagonal movement)</li> |
| <li>✅ Configurable close delay</li> |
| <li>✅ Sibling submenus auto-close</li> |
| </ul> |
| </div> |
| <div class="col-md-6"> |
| <h5>Keyboard Navigation</h5> |
| <ul class="feature-list"> |
| <li>✅ Arrow Up/Down - navigate items</li> |
| <li>✅ Arrow Right - enter submenu (Left in RTL)</li> |
| <li>✅ Arrow Left - exit submenu (Right in RTL)</li> |
| <li>✅ Enter/Space - activate item or open submenu</li> |
| <li>✅ Escape - close current submenu or menu</li> |
| <li>✅ Home/End - jump to first/last item</li> |
| </ul> |
| </div> |
| <div class="col-md-6"> |
| <h5>Viewport Detection</h5> |
| <ul class="feature-list"> |
| <li>✅ Default: opens to inline-end (right in LTR)</li> |
| <li>✅ Flips to inline-start when not enough space</li> |
| <li>✅ Shift to stay within viewport</li> |
| <li>✅ Auto-update on scroll/resize</li> |
| </ul> |
| </div> |
| <div class="col-md-6"> |
| <h5>Mobile Mode</h5> |
| <ul class="feature-list"> |
| <li>✅ Slide-over animation</li> |
| <li>✅ Back button navigation</li> |
| <li>✅ Full-screen submenu panels</li> |
| <li>✅ Configurable breakpoint</li> |
| </ul> |
| </div> |
| <div class="col-md-6"> |
| <h5>Accessibility</h5> |
| <ul class="feature-list"> |
| <li>✅ aria-haspopup on submenu triggers</li> |
| <li>✅ aria-expanded state management</li> |
| <li>✅ Focus management</li> |
| <li>✅ Focus returns to trigger on close</li> |
| </ul> |
| </div> |
| <div class="col-md-6"> |
| <h5>Configuration Options</h5> |
| <ul class="feature-list"> |
| <li>✅ submenuTrigger: 'click' | 'hover' | 'both'</li> |
| <li>✅ submenuDelay: close delay in ms</li> |
| <li>✅ mobileBreakpoint: px for mobile mode</li> |
| </ul> |
| </div> |
| </div> |
| </section> |
| </div> |
| |
| <script src="../../../dist/js/bootstrap.bundle.js"></script> |
| </body> |
| </html> |