diff --git a/docs/4.0/components/dropdowns.md b/docs/4.0/components/dropdowns.md
index 670ea5985453..b4c70478ef9e 100644
--- a/docs/4.0/components/dropdowns.md
+++ b/docs/4.0/components/dropdowns.md
@@ -671,6 +671,38 @@ Add `.disabled` to items in the dropdown to **style them as disabled**.
{% endexample %}
+## Dropdown options
+
+Use `data-offset` or `data-reference` to change the location of the dropdown.
+
+{% example html %}
+
+{% endexample %}
+
## Usage
Via data attributes or JavaScript, the dropdown plugin toggles hidden content (dropdown menus) by toggling the `.show` class on the parent list item. The `data-toggle="dropdown"` attribute is relied on for closing dropdown menus at an application level, so it's a good idea to always use it.
@@ -740,6 +772,12 @@ Options can be passed via data attributes or JavaScript. For data attributes, ap
'scrollParent'
Overflow constraint boundary of the dropdown menu. Accepts the values of 'viewport', 'window', 'scrollParent', or an HTMLElement reference (JavaScript only). For more information refer to Popper.js's preventOverflow docs.
+
+
reference
+
string | element
+
'toggle'
+
Reference element of the dropdown menu. Accepts the values of 'toggle', 'parent', or an HTMLElement reference. For more information refer to Popper.js's referenceObject docs.
+
diff --git a/js/src/dropdown.js b/js/src/dropdown.js
index 2ee37f628abf..82deaa220522 100644
--- a/js/src/dropdown.js
+++ b/js/src/dropdown.js
@@ -74,13 +74,15 @@ const Dropdown = (($) => {
const Default = {
offset : 0,
flip : true,
- boundary : 'scrollParent'
+ boundary : 'scrollParent',
+ reference : 'toggle'
}
const DefaultType = {
offset : '(number|string|function)',
flip : 'boolean',
- boundary : '(string|element)'
+ boundary : '(string|element)',
+ reference : '(string|element)'
}
/**
@@ -150,20 +152,27 @@ const Dropdown = (($) => {
if (typeof Popper === 'undefined') {
throw new TypeError('Bootstrap dropdown require Popper.js (https://popper.js.org)')
}
- let element = this._element
- // For dropup with alignment we use the parent as popper container
- if ($(parent).hasClass(ClassName.DROPUP)) {
- if ($(this._menu).hasClass(ClassName.MENULEFT) || $(this._menu).hasClass(ClassName.MENURIGHT)) {
- element = parent
+
+ let referenceElement = this._element
+
+ if (this._config.reference === 'parent') {
+ referenceElement = parent
+ } else if (Util.isElement(this._config.reference)) {
+ referenceElement = this._config.reference
+
+ // Check if it's jQuery element
+ if (typeof this._config.reference.jquery !== 'undefined') {
+ referenceElement = this._config.reference[0]
}
}
+
// If boundary is not `scrollParent`, then set position to `static`
// to allow the menu to "escape" the scroll parent's boundaries
// https://github.com/twbs/bootstrap/issues/24251
if (this._config.boundary !== 'scrollParent') {
$(parent).addClass(ClassName.POSITION_STATIC)
}
- this._popper = new Popper(element, this._menu, this._getPopperConfig())
+ this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig())
}
// If this is a touch-enabled device we add extra
diff --git a/js/tests/visual/dropdown.html b/js/tests/visual/dropdown.html
index b2e588677cd4..27a888f04048 100644
--- a/js/tests/visual/dropdown.html
+++ b/js/tests/visual/dropdown.html
@@ -161,8 +161,34 @@