mirror of https://github.com/twbs/bootstrap.git
483 lines
22 KiB
HTML
483 lines
22 KiB
HTML
<!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>Dropdown 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">Dropdown Submenus <small class="text-body-secondary">Bootstrap Visual Test</small></h1>
|
|
|
|
<div class="alert alert-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="text-body-secondary">Single level submenu with hover and click activation.</p>
|
|
|
|
<div class="demo-box">
|
|
<div class="dropdown">
|
|
<button class="btn btn-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Dropdown with Submenu
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Action</a></li>
|
|
<li><a class="dropdown-item" href="#">Another action</a></li>
|
|
<li class="dropdown-divider"></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
More options
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Sub-action 1</a></li>
|
|
<li><a class="dropdown-item" href="#">Sub-action 2</a></li>
|
|
<li><a class="dropdown-item" href="#">Sub-action 3</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="dropdown-item" href="#">Something else</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Nested Submenus -->
|
|
<section class="test-section">
|
|
<h2>Nested Submenus (Multi-level)</h2>
|
|
<p class="text-body-secondary">Three levels of nested submenus.</p>
|
|
|
|
<div class="demo-box">
|
|
<div class="dropdown">
|
|
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Multi-level Menu
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Level 1 - Action</a></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Level 1 - Submenu
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Level 2 - Action</a></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Level 2 - Submenu
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Level 3 - Action A</a></li>
|
|
<li><a class="dropdown-item" href="#">Level 3 - Action B</a></li>
|
|
<li><a class="dropdown-item" href="#">Level 3 - Action C</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="dropdown-item" href="#">Level 2 - Another</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="dropdown-item" href="#">Level 1 - Another</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Multiple Submenus -->
|
|
<section class="test-section">
|
|
<h2>Multiple Submenus at Same Level</h2>
|
|
<p class="text-body-secondary">Multiple submenu triggers in the same menu - opening one closes the other.</p>
|
|
|
|
<div class="demo-box">
|
|
<div class="dropdown">
|
|
<button class="btn btn-info dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Multiple Submenus
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
File operations
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">New</a></li>
|
|
<li><a class="dropdown-item" href="#">Open</a></li>
|
|
<li><a class="dropdown-item" href="#">Save</a></li>
|
|
<li><a class="dropdown-item" href="#">Save As...</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Edit operations
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Cut</a></li>
|
|
<li><a class="dropdown-item" href="#">Copy</a></li>
|
|
<li><a class="dropdown-item" href="#">Paste</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
View options
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Zoom In</a></li>
|
|
<li><a class="dropdown-item" href="#">Zoom Out</a></li>
|
|
<li><a class="dropdown-item" href="#">Fit to Window</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item" href="#">Preferences</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Viewport Flipping Test -->
|
|
<section class="test-section">
|
|
<h2>Viewport Detection (Flipping)</h2>
|
|
<p class="text-body-secondary">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 class="dropdown">
|
|
<button class="btn btn-success dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Left Side (opens right)
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Action</a></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Submenu
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Sub-action 1</a></li>
|
|
<li><a class="dropdown-item" href="#">Sub-action 2</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="dropdown">
|
|
<button class="btn btn-success dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Right Side (flips left)
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Action</a></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Submenu (should flip)
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Sub-action 1</a></li>
|
|
<li><a class="dropdown-item" href="#">Sub-action 2</a></li>
|
|
<li><a class="dropdown-item" href="#">Sub-action 3</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Navbar Integration -->
|
|
<section class="test-section">
|
|
<h2>Navbar Integration</h2>
|
|
<p class="text-body-secondary">Submenus work within navbar dropdowns.</p>
|
|
|
|
<nav class="navbar navbar-expand-lg 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 dropdown">
|
|
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Products
|
|
</a>
|
|
<ul class="dropdown-menu">
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Electronics
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Phones</a></li>
|
|
<li><a class="dropdown-item" href="#">Laptops</a></li>
|
|
<li><a class="dropdown-item" href="#">Tablets</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Clothing
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Men's</a></li>
|
|
<li><a class="dropdown-item" href="#">Women's</a></li>
|
|
<li><a class="dropdown-item" href="#">Kids</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="dropdown-divider"></li>
|
|
<li><a class="dropdown-item" href="#">All Products</a></li>
|
|
</ul>
|
|
</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="text-body-secondary">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 btn-warning dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Dropup Menu
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Action</a></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
More options
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Sub-action 1</a></li>
|
|
<li><a class="dropdown-item" href="#">Sub-action 2</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="dropdown-item" href="#">Something else</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- With Icons -->
|
|
<section class="test-section">
|
|
<h2>With Icons</h2>
|
|
<p class="text-body-secondary">Submenus with icons in menu items.</p>
|
|
|
|
<div class="demo-box">
|
|
<div class="dropdown">
|
|
<button class="btn btn-dark dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Menu with Icons
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li>
|
|
<a class="dropdown-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>
|
|
</li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-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>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Documents</a></li>
|
|
<li><a class="dropdown-item" href="#">Downloads</a></li>
|
|
<li><a class="dropdown-item" href="#">Pictures</a></li>
|
|
</ul>
|
|
</li>
|
|
<li class="dropdown-divider"></li>
|
|
<li>
|
|
<a class="dropdown-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>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Mobile Test -->
|
|
<section class="test-section">
|
|
<h2>Mobile Mode</h2>
|
|
<p class="text-body-secondary">
|
|
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 class="dropdown">
|
|
<button class="btn btn-danger dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Test on Mobile
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Action</a></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Navigate to submenu
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Sub-action 1</a></li>
|
|
<li><a class="dropdown-item" href="#">Sub-action 2</a></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Even deeper
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Deep action 1</a></li>
|
|
<li><a class="dropdown-item" href="#">Deep action 2</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
<li><a class="dropdown-item" href="#">Something else</a></li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Disabled Items -->
|
|
<section class="test-section">
|
|
<h2>With Disabled Items</h2>
|
|
<p class="text-body-secondary">Keyboard navigation skips disabled items.</p>
|
|
|
|
<div class="demo-box">
|
|
<div class="dropdown">
|
|
<button class="btn btn-outline-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
Menu with Disabled
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Enabled action</a></li>
|
|
<li><a class="dropdown-item disabled" href="#">Disabled action</a></li>
|
|
<li class="dropdown-submenu">
|
|
<button class="dropdown-item" type="button">
|
|
Submenu
|
|
</button>
|
|
<ul class="dropdown-menu">
|
|
<li><a class="dropdown-item" href="#">Enabled</a></li>
|
|
<li><a class="dropdown-item disabled" href="#">Disabled</a></li>
|
|
<li><a class="dropdown-item" href="#">Enabled</a></li>
|
|
</ul>
|
|
</li>
|
|
</ul>
|
|
</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 dropdown</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>
|