',
diff --git a/scss/_nav-overflow.scss b/scss/_nav-overflow.scss
index 780916095f2f..3cb25b10a516 100644
--- a/scss/_nav-overflow.scss
+++ b/scss/_nav-overflow.scss
@@ -13,6 +13,16 @@
container-type: inline-size;
flex: 1 1 0; // Fill the free space when the wrapper is itself a flex item
min-width: 0; // Let the wrapper shrink below its content width
+
+ // Prevent the expanded nav from flashing or creating a scrollbar before
+ // JavaScript completes the first overflow calculation.
+ &:not(.nav-overflow-initialized) {
+ overflow: clip;
+
+ > .nav {
+ visibility: hidden;
+ }
+ }
}
// The nav fills the wrapper and stops wrapping, so items run past the edge in
@@ -34,6 +44,11 @@
margin-inline-start: auto;
}
+ // Remove the inline line box so an icon-only toggle centers its icon.
+ .nav-overflow-icon {
+ display: flex;
+ }
+
// Hide items that have been moved to overflow
.nav-overflow [data-bs-nav-overflow="true"] {
display: none;
diff --git a/scss/_nav.scss b/scss/_nav.scss
index 53fc2728b409..464309d7c2a0 100644
--- a/scss/_nav.scss
+++ b/scss/_nav.scss
@@ -59,10 +59,10 @@ $nav-pills-tokens: defaults(
(
--nav-pills-bg: var(--bg-1),
--nav-pills-padding: .25rem,
- --nav-pills-border-radius: var(--radius-9),
+ --nav-pills-border-radius: 3rem,
--nav-pills-link-active-color: var(--primary-contrast),
--nav-pills-link-active-bg: var(--primary-bg),
- --nav-pills-link-border-radius: var(--radius-9),
+ --nav-pills-link-border-radius: 3rem,
),
$nav-pills-tokens
);
diff --git a/site/src/components/shortcodes/ResizableExample.astro b/site/src/components/shortcodes/ResizableExample.astro
index f470c5e4414d..105f823070af 100644
--- a/site/src/components/shortcodes/ResizableExample.astro
+++ b/site/src/components/shortcodes/ResizableExample.astro
@@ -57,11 +57,17 @@ markup = replacePlaceholdersInHtml(markup)
// The resizable container needs `overflow: hidden` for the CSS `resize` handle
// to work, which clips popovers like menus/dropdowns when they open. Render them
// with a fixed positioning strategy in the live preview only so they can spill
-// outside the container. The displayed markup below is left untouched.
-const previewMarkup = markup.replace(
- /data-bs-toggle="(menu|dropdown)"(?![^>]*\bdata-bs-strategy=)/g,
- 'data-bs-toggle="$1" data-bs-strategy="fixed"'
-)
+// outside the container. NavOverflow passes its strategy to the toggle that it
+// generates. The displayed markup below is left untouched.
+const previewMarkup = markup
+ .replace(
+ /data-bs-toggle="(menu|dropdown)"(?![^>]*\bdata-bs-strategy=)/g,
+ 'data-bs-toggle="$1" data-bs-strategy="fixed"'
+ )
+ .replace(
+ /data-bs-toggle="nav-overflow"(?![^>]*\bdata-bs-menu-strategy=)/g,
+ 'data-bs-toggle="nav-overflow" data-bs-menu-strategy="fixed"'
+ )
const simplifiedMarkup = markup.replace(
//g,
diff --git a/site/src/content/docs/components/nav-overflow.mdx b/site/src/content/docs/components/nav-overflow.mdx
index 686acb5d25c7..f2120d2e600d 100644
--- a/site/src/content/docs/components/nav-overflow.mdx
+++ b/site/src/content/docs/components/nav-overflow.mdx
@@ -15,7 +15,7 @@ Here’s what you need to know before getting started:
- Wrap your `.nav` in a `.nav-overflow` element and add `data-bs-toggle="nav-overflow"` to that wrapper.
- **Responds to container size**, not viewport size. The component watches the wrapper with a ResizeObserver, so it works in embedded contexts, documentation examples, and responsive containers.
- The wrapper is what makes this reliable. Collapsing items changes the width of the nav, so the component measures the wrapper instead. Measuring the nav would feed the result back in as the input.
-- Overflow items are cloned into a "More" menu while the originals are hidden.
+- Overflow items are cloned into a "More" menu while the originals are hidden. A nav item that hosts a menu is the exception: its `.menu` moves into a submenu of the overflow menu.
- Works with all nav styles: default, pills, tabs, and underline.
- Active and disabled states are preserved in the overflow menu.
@@ -195,6 +195,59 @@ The nav overflow pattern can also be used within a [navbar]([[docsref:/component
`} />
+### With menus
+
+A nav item that already hosts a [menu]([[docsref:/components/menu]]) becomes a submenu of the overflow menu. The plugin moves the original `.menu` rather than cloning it, so nested submenus stay intact.
+
+
+
`} />
+
## Customizing the toggle
### Custom text
@@ -347,6 +400,7 @@ const navOverflow = new bootstrap.NavOverflow(wrapperElement, {
| `collapseBelow` | number\|string | `0` | Wrapper width below which all items collapse into the overflow dropdown. Pass a breakpoint name (e.g., `'md'`) to resolve from `--bs-breakpoint-{name}`, or a number for a direct pixel value. `0` disables. |
| `iconPlacement` | string | `'start'` | Position of the icon relative to the text in the toggle button. Use `'start'` for before the text or `'end'` for after. |
| `menuPlacement` | string | `'bottom-end'` | Placement of the overflow dropdown menu, passed as `data-bs-placement` to the menu toggle. |
+| `menuStrategy` | string | `'absolute'` | Positioning strategy for the overflow menu, passed as `data-bs-strategy` to the menu toggle. Use `'fixed'` when an overflow ancestor would clip the menu. |
| `moreText` | string\|boolean | `'More'` | Text label for the overflow toggle button. Inserted as plain text. Use `false` (or an empty string) for an icon-only toggle, which is labeled `aria-label="More"` instead. |
| `moreIcon` | string | `''` | SVG or HTML icon for the overflow toggle button. Passed through the [icon content sanitizer]([[docsref:/getting-started/javascript#sanitizer]]) before insertion. Overridden by a child element with `data-bs-overflow-icon` if present (also sanitized). |
| `threshold` | number | `0` | Minimum number of items to keep visible before showing overflow. |