diff --git a/build/generate-sri.js b/build/generate-sri.js
index cde818e090f6b1c216ff33f3ca8741d541b90eb5..ac897565f0b0cf7343608b8737a8033bc1ed6286 100644
--- a/build/generate-sri.js
+++ b/build/generate-sri.js
@@ -42,8 +42,8 @@ const files = [
     configPropertyName: 'js_bundle_hash'
   },
   {
-    file: 'node_modules/@popperjs/core/dist/umd/popper.min.js',
-    configPropertyName: 'popper_hash'
+    file: 'node_modules/@floating-ui/dom/dist/floating-ui.dom.umd.js',
+    configPropertyName: 'floating_ui_hash'
   }
 ]
 
diff --git a/build/rollup.config.js b/build/rollup.config.js
index 2d2920fd50d41ddbf0964a15278438d7d0e379cf..3a9d4d706d79fde871ce6e6156cd36b387815517 100644
--- a/build/rollup.config.js
+++ b/build/rollup.config.js
@@ -10,7 +10,7 @@ const BUNDLE = process.env.BUNDLE === 'true'
 const ESM = process.env.ESM === 'true'
 
 let fileDestination = `bootstrap${ESM ? '.esm' : ''}`
-const external = ['@popperjs/core']
+const external = ['@floating-ui/dom']
 const plugins = [
   babel({
     // Only transpile our source code
@@ -20,14 +20,14 @@ const plugins = [
   })
 ]
 const globals = {
-  '@popperjs/core': 'Popper'
+  '@floating-ui/dom': 'floatingUi'
 }
 
 if (BUNDLE) {
   fileDestination += '.bundle'
   // Remove last entry in external array to bundle Popper
   external.pop()
-  delete globals['@popperjs/core']
+  delete globals['@floating-ui/dom']
   plugins.push(
     replace({
       'process.env.NODE_ENV': '"production"',
diff --git a/config.yml b/config.yml
index bb71b8d0ca1d2563c0015860d06c9187f322c11b..62e99f77d44ac8a4924fb72911c56d9a8453ce71 100644
--- a/config.yml
+++ b/config.yml
@@ -80,8 +80,8 @@ params:
     js_hash:          "sha384-ODmDIVzN+pFdexxHEHFBQH3/9/vQ9uori45z4JjnFsRydbmQbmL5t1tQ0culUzyK"
     js_bundle:        "https://cdn.jsdelivr.net/npm/bootstrap@5.2.0/dist/js/bootstrap.bundle.min.js"
     js_bundle_hash:   "sha384-A3rJD856KowSb7dwlZdYEkO39Gagi7vIsF0jrRAoQmDKKtQBHUuLZ9AsSv4jD4Xa"
-    popper:           "https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.5/dist/umd/popper.min.js"
-    popper_hash:      "sha384-Xe+8cL9oJa6tN/veChSP7q+mnSPaj5Bcu9mPX5F5xIGE0DVittaqT5lorf0EI7Vk"
+    floating_ui: "https://cdn.jsdelivr.net/npm/@floating-ui/dom@0.5.4/dist/floating-ui.dom.umd.min.js"
+    floating_ui_hash: "sha384-Os8n9bzoYJ/ESbGD7cW0VOTLk0hO++SO+Y4swXBE2dHrxiZkjADEr5ZGOcc9CorD"
 
   anchors:
     min: 2
diff --git a/js/src/dropdown.js b/js/src/dropdown.js
index 601792953e0340fe452bdebe8140481b8653a841..a969fa838a05b7715f038bffd0c24f645adc2444 100644
--- a/js/src/dropdown.js
+++ b/js/src/dropdown.js
@@ -5,21 +5,18 @@
  * --------------------------------------------------------------------------
  */
 
-import * as Popper from '@popperjs/core'
+import { inline, offset, shift } from '@floating-ui/dom'
 import {
   defineJQueryPlugin,
-  getElement,
   getNextActiveElement,
   isDisabled,
-  isElement,
-  isRTL,
   isVisible,
   noop
 } from './util/index'
 import EventHandler from './dom/event-handler'
-import Manipulator from './dom/manipulator'
 import SelectorEngine from './dom/selector-engine'
 import BaseComponent from './base-component'
+import FloatingUi from './util/floating-ui'
 
 /**
  * Constants
@@ -28,7 +25,6 @@ import BaseComponent from './base-component'
 const NAME = 'dropdown'
 const DATA_KEY = 'bs.dropdown'
 const EVENT_KEY = `.${DATA_KEY}`
-const DATA_API_KEY = '.data-api'
 
 const ESCAPE_KEY = 'Escape'
 const TAB_KEY = 'Tab'
@@ -40,9 +36,9 @@ const EVENT_HIDE = `hide${EVENT_KEY}`
 const EVENT_HIDDEN = `hidden${EVENT_KEY}`
 const EVENT_SHOW = `show${EVENT_KEY}`
 const EVENT_SHOWN = `shown${EVENT_KEY}`
-const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
-const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
-const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`
+const EVENT_CLICK_DATA_API = `click${EVENT_KEY}`
+const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}`
+const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}`
 
 const CLASS_NAME_SHOW = 'show'
 const CLASS_NAME_DROPUP = 'dropup'
@@ -58,30 +54,28 @@ const SELECTOR_NAVBAR = '.navbar'
 const SELECTOR_NAVBAR_NAV = '.navbar-nav'
 const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
 
-const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'
-const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'
-const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'
-const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'
-const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'
-const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'
 const PLACEMENT_TOPCENTER = 'top'
+const PLACEMENT_TOPEND = 'top-end'
+const PLACEMENT_TOP = 'top-start'
 const PLACEMENT_BOTTOMCENTER = 'bottom'
+const PLACEMENT_BOTTOMEND = 'bottom-end'
+const PLACEMENT_BOTTOM = 'bottom-start'
+const PLACEMENT_RIGHT = 'right-start'
+const PLACEMENT_LEFT = 'left-start'
 
 const Default = {
   autoClose: true,
-  boundary: 'clippingParents',
   display: 'dynamic',
-  offset: [0, 2],
-  popperConfig: null,
+  offset: 10,
+  positionConfig: null,
   reference: 'toggle'
 }
 
 const DefaultType = {
   autoClose: '(boolean|string)',
-  boundary: '(string|element)',
   display: 'string',
-  offset: '(array|string|function)',
-  popperConfig: '(null|object|function)',
+  offset: '(number|array|string|function)',
+  positionConfig: '(null|object|function)',
   reference: '(string|element|object)'
 }
 
@@ -93,10 +87,9 @@ class Dropdown extends BaseComponent {
   constructor(element, config) {
     super(element, config)
 
-    this._popper = null
     this._parent = this._element.parentNode // dropdown wrapper
     this._menu = SelectorEngine.findOne(SELECTOR_MENU, this._parent)
-    this._inNavbar = this._detectNavbar()
+    this._positionHelper = new FloatingUi(this._element)
   }
 
   // Getters
@@ -132,7 +125,7 @@ class Dropdown extends BaseComponent {
       return
     }
 
-    this._createPopper()
+    this.update()
 
     // If this is a touch-enabled device we add extra
     // empty mouseover listeners to the body's immediate children;
@@ -164,19 +157,9 @@ class Dropdown extends BaseComponent {
     this._completeHide(relatedTarget)
   }
 
-  dispose() {
-    if (this._popper) {
-      this._popper.destroy()
-    }
-
-    super.dispose()
-  }
-
   update() {
-    this._inNavbar = this._detectNavbar()
-    if (this._popper) {
-      this._popper.update()
-    }
+    const reference = this._positionHelper.getReferenceElement(this._config.reference, this._parent, NAME)
+    this._positionHelper.calculate(reference, this._menu, this._getFloatingUiConfig())
   }
 
   // Private
@@ -194,47 +177,28 @@ class Dropdown extends BaseComponent {
       }
     }
 
-    if (this._popper) {
-      this._popper.destroy()
-    }
-
     this._menu.classList.remove(CLASS_NAME_SHOW)
     this._element.classList.remove(CLASS_NAME_SHOW)
     this._element.setAttribute('aria-expanded', 'false')
-    Manipulator.removeDataAttribute(this._menu, 'popper')
+    this._positionHelper.stop()
     EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
   }
 
-  _getConfig(config) {
-    config = super._getConfig(config)
-
-    if (typeof config.reference === 'object' && !isElement(config.reference) &&
-      typeof config.reference.getBoundingClientRect !== 'function'
-    ) {
-      // Popper virtual elements require a getBoundingClientRect method
-      throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
+  _getFloatingUiConfig() {
+    const defaultBsConfig = {
+      placement: this._getPlacement(),
+      middleware: [offset(this._positionHelper.parseOffset(this._config.offset)), shift()]
     }
 
-    return config
-  }
-
-  _createPopper() {
-    if (typeof Popper === 'undefined') {
-      throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
+    // Disable Popper if we have a static display or Dropdown is in Navbar
+    if (this._detectNavbar() || this._config.display === 'static') {
+      defaultBsConfig.middleware.push(inline())
     }
 
-    let referenceElement = this._element
-
-    if (this._config.reference === 'parent') {
-      referenceElement = this._parent
-    } else if (isElement(this._config.reference)) {
-      referenceElement = getElement(this._config.reference)
-    } else if (typeof this._config.reference === 'object') {
-      referenceElement = this._config.reference
+    return {
+      ...defaultBsConfig,
+      ...(typeof this._config.positionConfig === 'function' ? this._config.positionConfig(defaultBsConfig) : this._config.positionConfig)
     }
-
-    const popperConfig = this._getPopperConfig()
-    this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)
   }
 
   _isShown() {
@@ -244,20 +208,15 @@ class Dropdown extends BaseComponent {
   _getPlacement() {
     const parentDropdown = this._parent
 
-    if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
-      return PLACEMENT_RIGHT
+    const matches = {
+      [CLASS_NAME_DROPEND]: PLACEMENT_RIGHT,
+      [CLASS_NAME_DROPSTART]: PLACEMENT_LEFT,
+      [CLASS_NAME_DROPUP_CENTER]: PLACEMENT_TOPCENTER,
+      [CLASS_NAME_DROPDOWN_CENTER]: PLACEMENT_BOTTOMCENTER
     }
-
-    if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
-      return PLACEMENT_LEFT
-    }
-
-    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {
-      return PLACEMENT_TOPCENTER
-    }
-
-    if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {
-      return PLACEMENT_BOTTOMCENTER
+    const match = Object.keys(matches).find(keyClass => parentDropdown.classList.contains(keyClass))
+    if (match) {
+      return matches[match]
     }
 
     // We need to trim the value because custom properties can also include spaces
@@ -274,52 +233,6 @@ class Dropdown extends BaseComponent {
     return this._element.closest(SELECTOR_NAVBAR) !== null
   }
 
-  _getOffset() {
-    const { offset } = this._config
-
-    if (typeof offset === 'string') {
-      return offset.split(',').map(value => Number.parseInt(value, 10))
-    }
-
-    if (typeof offset === 'function') {
-      return popperData => offset(popperData, this._element)
-    }
-
-    return offset
-  }
-
-  _getPopperConfig() {
-    const defaultBsPopperConfig = {
-      placement: this._getPlacement(),
-      modifiers: [{
-        name: 'preventOverflow',
-        options: {
-          boundary: this._config.boundary
-        }
-      },
-      {
-        name: 'offset',
-        options: {
-          offset: this._getOffset()
-        }
-      }]
-    }
-
-    // Disable Popper if we have a static display or Dropdown is in Navbar
-    if (this._inNavbar || this._config.display === 'static') {
-      Manipulator.setDataAttribute(this._menu, 'popper', 'static') // todo:v6 remove
-      defaultBsPopperConfig.modifiers = [{
-        name: 'applyStyles',
-        enabled: false
-      }]
-    }
-
-    return {
-      ...defaultBsPopperConfig,
-      ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
-    }
-  }
-
   _selectMenuItem({ key, target }) {
     const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))
 
@@ -364,11 +277,7 @@ class Dropdown extends BaseComponent {
 
       const composedPath = event.composedPath()
       const isMenuTarget = composedPath.includes(context._menu)
-      if (
-        composedPath.includes(context._element) ||
-        (context._config.autoClose === 'inside' && !isMenuTarget) ||
-        (context._config.autoClose === 'outside' && isMenuTarget)
-      ) {
+      if (composedPath.includes(context._element) || (context._config.autoClose === 'inside' && !isMenuTarget) || (context._config.autoClose === 'outside' && isMenuTarget)) {
         continue
       }
 
diff --git a/js/src/popover.js b/js/src/popover.js
index acfd1ac79103c4a6afa083223c95e33588cbcd45..c82cd0bc4d28adaee158de4a9dc63cacbfca3813 100644
--- a/js/src/popover.js
+++ b/js/src/popover.js
@@ -23,9 +23,10 @@ const Default = {
   offset: [0, 8],
   placement: 'right',
   template: '<div class="popover" role="tooltip">' +
-    '<div class="popover-arrow"></div>' +
+    '<div class="popover-inner">' +
     '<h3 class="popover-header"></h3>' +
     '<div class="popover-body"></div>' +
+    '</div>' +
     '</div>',
   trigger: 'click'
 }
diff --git a/js/src/tooltip.js b/js/src/tooltip.js
index 2c5f03a29340d066267105899e9e4cd647717e1b..dfd973767b97375e05ece4f67da695d7a7901629 100644
--- a/js/src/tooltip.js
+++ b/js/src/tooltip.js
@@ -5,13 +5,14 @@
  * --------------------------------------------------------------------------
  */
 
-import * as Popper from '@popperjs/core'
-import { defineJQueryPlugin, findShadowRoot, getElement, getUID, isRTL, noop } from './util/index'
+import { defineJQueryPlugin, findShadowRoot, getElement, getUID, isVisible, noop } from './util/index'
 import { DefaultAllowlist } from './util/sanitizer'
 import EventHandler from './dom/event-handler'
 import Manipulator from './dom/manipulator'
 import BaseComponent from './base-component'
 import TemplateFactory from './util/template-factory'
+import FloatingUi from './util/floating-ui'
+import { flip, hide, offset, shift } from '@floating-ui/dom'
 
 /**
  * Constants
@@ -48,9 +49,9 @@ const EVENT_MOUSELEAVE = 'mouseleave'
 const AttachmentMap = {
   AUTO: 'auto',
   TOP: 'top',
-  RIGHT: isRTL() ? 'left' : 'right',
+  RIGHT: 'right',
   BOTTOM: 'bottom',
-  LEFT: isRTL() ? 'right' : 'left'
+  LEFT: 'left'
 }
 
 const Default = {
@@ -62,16 +63,15 @@ const Default = {
   delay: 0,
   fallbackPlacements: ['top', 'right', 'bottom', 'left'],
   html: false,
-  offset: [0, 0],
+  offset: 0,
   placement: 'top',
-  popperConfig: null,
+  positionConfig: null,
   sanitize: true,
   sanitizeFn: null,
   selector: false,
   template: '<div class="tooltip" role="tooltip">' +
-            '<div class="tooltip-arrow"></div>' +
-            '<div class="tooltip-inner"></div>' +
-            '</div>',
+    '<div class="tooltip-inner"></div>' +
+    '</div>',
   title: '',
   trigger: 'hover focus'
 }
@@ -85,9 +85,9 @@ const DefaultType = {
   delay: '(number|object)',
   fallbackPlacements: 'array',
   html: 'boolean',
-  offset: '(array|string|function)',
+  offset: '(number|array|string|function)',
   placement: '(string|function)',
-  popperConfig: '(null|object|function)',
+  positionConfig: '(null|object|function)',
   sanitize: 'boolean',
   sanitizeFn: '(null|function)',
   selector: '(string|boolean)',
@@ -102,10 +102,6 @@ const DefaultType = {
 
 class Tooltip extends BaseComponent {
   constructor(element, config) {
-    if (typeof Popper === 'undefined') {
-      throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)')
-    }
-
     super(element, config)
 
     // Private
@@ -113,7 +109,7 @@ class Tooltip extends BaseComponent {
     this._timeout = 0
     this._isHovered = false
     this._activeTrigger = {}
-    this._popper = null
+    this._positionHelper = new FloatingUi(this._element)
     this._templateFactory = null
     this._newContent = null
 
@@ -194,7 +190,7 @@ class Tooltip extends BaseComponent {
   }
 
   show() {
-    if (this._element.style.display === 'none') {
+    if (!isVisible(this._element)) {
       throw new Error('Please use show on visible elements')
     }
 
@@ -216,24 +212,9 @@ class Tooltip extends BaseComponent {
       this.tip = null
     }
 
-    const tip = this._getTipElement()
-
-    this._element.setAttribute('aria-describedby', tip.getAttribute('id'))
-
-    const { container } = this._config
-
-    if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
-      container.append(tip)
-      EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))
-    }
+    this.update()
 
-    if (this._popper) {
-      this._popper.update()
-    } else {
-      this._popper = this._createPopper(tip)
-    }
-
-    tip.classList.add(CLASS_NAME_SHOW)
+    this.tip.classList.add(CLASS_NAME_SHOW)
 
     // If this is a touch-enabled device we add extra
     // empty mouseover listeners to the body's immediate children;
@@ -291,24 +272,17 @@ class Tooltip extends BaseComponent {
       }
 
       if (!this._isHovered) {
+        this._positionHelper.stop()
         tip.remove()
       }
 
       this._element.removeAttribute('aria-describedby')
       EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))
-
-      this._disposePopper()
     }
 
     this._queueCallback(complete, this.tip, this._isAnimated())
   }
 
-  update() {
-    if (this._popper) {
-      this._popper.update()
-    }
-  }
-
   // Protected
   _isWithContent() {
     return Boolean(this._getTitle())
@@ -317,6 +291,14 @@ class Tooltip extends BaseComponent {
   _getTipElement() {
     if (!this.tip) {
       this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())
+      this._element.setAttribute('aria-describedby', this.tip.getAttribute('id'))
+    }
+
+    const { container } = this._config
+
+    if (!this._element.ownerDocument.documentElement.contains(this.tip)) {
+      container.append(this.tip)
+      EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))
     }
 
     return this.tip
@@ -331,8 +313,6 @@ class Tooltip extends BaseComponent {
     }
 
     tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)
-    // todo: on v6 the following can be achieved with CSS only
-    tip.classList.add(`bs-${this.constructor.NAME}-auto`)
 
     const tipId = getUID(this.constructor.NAME).toString()
 
@@ -392,79 +372,39 @@ class Tooltip extends BaseComponent {
     return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)
   }
 
-  _createPopper(tip) {
-    const placement = typeof this._config.placement === 'function' ?
-      this._config.placement.call(this, tip, this._element) :
-      this._config.placement
-    const attachment = AttachmentMap[placement.toUpperCase()]
-    return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))
-  }
-
-  _getOffset() {
-    const { offset } = this._config
-
-    if (typeof offset === 'string') {
-      return offset.split(',').map(value => Number.parseInt(value, 10))
+  update() {
+    this._positionHelper.calculate(this._element, this._getTipElement(), this._getFloatingUiConfig(), { position: 'fixed' })
+  }
+
+  _getFloatingUiConfig() {
+    const defaultBsConfig = {
+      strategy: 'fixed',
+      placement: this._getPlacement(),
+      middleware: [
+        offset(this._positionHelper.parseOffset(this._config.offset)),
+        flip({ fallbackPlacements: this._config.fallbackPlacements }),
+        shift(),
+        hide()
+      ]
     }
 
-    if (typeof offset === 'function') {
-      return popperData => offset(popperData, this._element)
+    return {
+      ...defaultBsConfig,
+      ...(typeof this._config.positionConfig === 'function' ? this._config.positionConfig(defaultBsConfig) : this._config.positionConfig)
     }
+  }
 
-    return offset
+  _getPlacement() {
+    const placement = typeof this._config.placement === 'function' ?
+      this._config.placement.call(this, this.tip, this._element) :
+      this._config.placement
+    return AttachmentMap[placement.toUpperCase()]
   }
 
   _resolvePossibleFunction(arg) {
     return typeof arg === 'function' ? arg.call(this._element) : arg
   }
 
-  _getPopperConfig(attachment) {
-    const defaultBsPopperConfig = {
-      placement: attachment,
-      modifiers: [
-        {
-          name: 'flip',
-          options: {
-            fallbackPlacements: this._config.fallbackPlacements
-          }
-        },
-        {
-          name: 'offset',
-          options: {
-            offset: this._getOffset()
-          }
-        },
-        {
-          name: 'preventOverflow',
-          options: {
-            boundary: this._config.boundary
-          }
-        },
-        {
-          name: 'arrow',
-          options: {
-            element: `.${this.constructor.NAME}-arrow`
-          }
-        },
-        {
-          name: 'preSetPlacement',
-          enabled: true,
-          phase: 'beforeMain',
-          fn: data => {
-            // Pre-set Popper's placement attribute in order to read the arrow sizes properly.
-            // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement
-            this._getTipElement().setAttribute('data-popper-placement', data.state.placement)
-          }
-        }
-      ]
-    }
-
-    return {
-      ...defaultBsPopperConfig,
-      ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig)
-    }
-  }
-
   _setListeners() {
     const triggers = this._config.trigger.split(' ')
 
@@ -621,13 +561,6 @@ class Tooltip extends BaseComponent {
     return config
   }
 
-  _disposePopper() {
-    if (this._popper) {
-      this._popper.destroy()
-      this._popper = null
-    }
-  }
-
   // Static
   static jQueryInterface(config) {
     return this.each(function () {
diff --git a/js/src/util/floating-ui.js b/js/src/util/floating-ui.js
new file mode 100644
index 0000000000000000000000000000000000000000..5501daf85664b4d39c5fc03ec38c01766a12f6b8
--- /dev/null
+++ b/js/src/util/floating-ui.js
@@ -0,0 +1,92 @@
+// import {computePosition, flip, shift} from '@floating-ui/dom'
+//
+//
+import { autoUpdate, computePosition } from '@floating-ui/dom'
+import { getElement, isElement } from './index'
+import Manipulator from '../dom/manipulator'
+
+class FloatingUi {
+  constructor(element) {
+    if (typeof computePosition === 'undefined') {
+      throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)')
+    }
+
+    this._element = element
+    this._cleanup = null
+  }
+
+  calculate(reference, floatingEl, config, extraCss = {}) {
+    this._cleanup = autoUpdate(reference, floatingEl, () => {
+      computePosition(reference, floatingEl, config)
+        .then(({ x, y, placement, middlewareData }) => {
+          const positionCss = {
+            left: `${x}px`,
+            top: `${y}px`
+          }
+          console.log(middlewareData) // eslint-disable-line no-console
+          if (middlewareData.hide) {
+            const { referenceHidden } = middlewareData.hide
+
+            Object.assign(floatingEl.style, {
+              visibility: referenceHidden ? 'hidden' : 'visible'
+            })
+          }
+
+          Object.assign(floatingEl.style, { ...positionCss, ...extraCss })
+          Manipulator.setDataAttribute(floatingEl, 'placement', placement)
+        })
+    })
+  }
+
+  stop() {
+    if (this._cleanup) {
+      this._cleanup()
+    }
+  }
+
+  getReferenceElement(reference, parent, PluginName) {
+    if (reference === 'parent') {
+      return parent
+    }
+
+    if (isElement(reference)) {
+      return getElement(reference)
+    }
+
+    if (typeof reference === 'object') {
+      if (typeof reference.getBoundingClientRect !== 'function') {
+        throw new TypeError(`${PluginName.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
+      }
+
+      return reference
+    }
+
+    return this._element
+  }
+
+  parseOffset(value) {
+    console.log(value) // eslint-disable-line no-console
+    if (typeof value === 'function') {
+      return popperData => value(popperData, this._element)
+    }
+
+    if (typeof value === 'string') {
+      console.log('offset', value) // eslint-disable-line no-console
+      value = [
+        Number.parseInt(value.split(',')[0], 10),
+        Number.parseInt(value.split(',')[1] || 0, 10)
+      ]
+    }
+
+    if (Array.isArray(value)) {
+      return {
+        mainAxis: value[0],
+        alignmentAxis: value[1]
+      }
+    }
+
+    return value
+  }
+}
+
+export default FloatingUi
diff --git a/package-lock.json b/package-lock.json
index b2511343d0f6b5d7f8c9da0efba598e7eb078f50..4fd170f4874265bc924299d0cdde712b7e57f22d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,9 @@
         }
       ],
       "license": "MIT",
+      "dependencies": {
+        "@floating-ui/dom": "^0.5.4"
+      },
       "devDependencies": {
         "@babel/cli": "^7.18.10",
         "@babel/core": "^7.18.10",
@@ -1770,6 +1773,19 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/@floating-ui/core": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
+      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
+    },
+    "node_modules/@floating-ui/dom": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
+      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
+      "dependencies": {
+        "@floating-ui/core": "^0.7.3"
+      }
+    },
     "node_modules/@humanwhocodes/config-array": {
       "version": "0.10.4",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz",
@@ -11705,6 +11721,19 @@
         }
       }
     },
+    "@floating-ui/core": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
+      "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
+    },
+    "@floating-ui/dom": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
+      "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
+      "requires": {
+        "@floating-ui/core": "^0.7.3"
+      }
+    },
     "@humanwhocodes/config-array": {
       "version": "0.10.4",
       "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz",
diff --git a/package.json b/package.json
index 32ec47f86b954b422842c367b680dc79fd6b94c2..2cabf2a3cf04403fd82071665ce790ee0e6f4f16 100644
--- a/package.json
+++ b/package.json
@@ -101,13 +101,13 @@
     "watch-js-docs": "nodemon --watch site/assets/js/ --ext js --exec \"npm run js-lint\""
   },
   "peerDependencies": {
-    "@popperjs/core": "^2.11.5"
+      "@floating-ui/dom": "^0.5.4"
   },
   "devDependencies": {
     "@babel/cli": "^7.18.10",
     "@babel/core": "^7.18.10",
     "@babel/preset-env": "^7.18.10",
-    "@popperjs/core": "^2.11.5",
+    "@floating-ui/dom": "^0.5.4",
     "@rollup/plugin-babel": "^5.3.1",
     "@rollup/plugin-commonjs": "^22.0.1",
     "@rollup/plugin-node-resolve": "^13.3.0",
@@ -174,7 +174,7 @@
     },
     "dependencies": {},
     "peerDependencies": {
-      "@popperjs/core": "^2.11.5"
+        "@floating-ui/dom": "^0.5.4"
     }
   }
 }
diff --git a/scss/_dropdown.scss b/scss/_dropdown.scss
index 62125b96783a25934f469e7c5e270f1050d02c2c..de96a9e1bcb76ec7d42ed143be992afe7d9b8da1 100644
--- a/scss/_dropdown.scss
+++ b/scss/_dropdown.scss
@@ -61,12 +61,6 @@
   @include border-radius(var(--#{$prefix}dropdown-border-radius));
   @include box-shadow(var(--#{$prefix}dropdown-box-shadow));
 
-  &[data-bs-popper] {
-    top: 100%;
-    left: 0;
-    margin-top: var(--#{$prefix}dropdown-spacer);
-  }
-
   @if $dropdown-padding-y == 0 {
     > .dropdown-item:first-child,
     > li:first-child .dropdown-item {
@@ -82,7 +76,7 @@
 
 // scss-docs-start responsive-breakpoints
 // We deliberately hardcode the `bs-` prefix because we check
-// this custom property in JS to determine Popper's positioning
+// this custom property in JS to determine positioning
 
 @each $breakpoint in map-keys($grid-breakpoints) {
   @include media-breakpoint-up($breakpoint) {
@@ -90,20 +84,10 @@
 
     .dropdown-menu#{$infix}-start {
       --bs-position: start;
-
-      &[data-bs-popper] {
-        right: auto;
-        left: 0;
-      }
     }
 
     .dropdown-menu#{$infix}-end {
       --bs-position: end;
-
-      &[data-bs-popper] {
-        right: 0;
-        left: auto;
-      }
     }
   }
 }
@@ -112,26 +96,12 @@
 // Allow for dropdowns to go bottom up (aka, dropup-menu)
 // Just add .dropup after the standard .dropdown class and you're set.
 .dropup {
-  .dropdown-menu[data-bs-popper] {
-    top: auto;
-    bottom: 100%;
-    margin-top: 0;
-    margin-bottom: var(--#{$prefix}dropdown-spacer);
-  }
-
   .dropdown-toggle {
     @include caret(up);
   }
 }
 
 .dropend {
-  .dropdown-menu[data-bs-popper] {
-    top: 0;
-    right: auto;
-    left: 100%;
-    margin-top: 0;
-    margin-left: var(--#{$prefix}dropdown-spacer);
-  }
 
   .dropdown-toggle {
     @include caret(end);
@@ -142,14 +112,6 @@
 }
 
 .dropstart {
-  .dropdown-menu[data-bs-popper] {
-    top: 0;
-    right: 100%;
-    left: auto;
-    margin-top: 0;
-    margin-right: var(--#{$prefix}dropdown-spacer);
-  }
-
   .dropdown-toggle {
     @include caret(start);
     &::before {
diff --git a/scss/_popover.scss b/scss/_popover.scss
index b00c02959d595c1cc47e58be8f908ac393cb6e47..eb13efd12fd1d996178d38e4d5597f377fabe664 100644
--- a/scss/_popover.scss
+++ b/scss/_popover.scss
@@ -22,6 +22,9 @@
   --#{$prefix}popover-arrow-border: var(--#{$prefix}popover-border-color);
   // scss-docs-end popover-css-vars
 
+  position: absolute;
+  top: 0;
+  left: 0;
   z-index: var(--#{$prefix}popover-zindex);
   display: block;
   max-width: var(--#{$prefix}popover-max-width);
@@ -31,150 +34,122 @@
   @include font-size(var(--#{$prefix}popover-font-size));
   // Allow breaking very long words so they don't overflow the popover's bounds
   word-wrap: break-word;
+
+  &::before,
+  &::after {
+    position: absolute;
+    display: block;
+    content: "";
+    border-color: transparent;
+    border-style: solid;
+    border-width: 0;
+    transform: translateX(-50%);
+  }
+}
+
+.popover-inner {
+  margin: var(--#{$prefix}popover-arrow-height);
   background-color: var(--#{$prefix}popover-bg);
   background-clip: padding-box;
   border: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color);
   @include border-radius(var(--#{$prefix}popover-border-radius));
   @include box-shadow(var(--#{$prefix}popover-box-shadow));
-
-  .popover-arrow {
-    display: block;
-    width: var(--#{$prefix}popover-arrow-width);
-    height: var(--#{$prefix}popover-arrow-height);
-
-    &::before,
-    &::after {
-      position: absolute;
-      display: block;
-      content: "";
-      border-color: transparent;
-      border-style: solid;
-      border-width: 0;
-    }
-  }
 }
 
-.bs-popover-top {
-  > .popover-arrow {
-    bottom: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
-
-    &::before,
-    &::after {
-      border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
-    }
+.popover[data-bs-placement="top"] {
+  &::before,
+  &::after {
+    left: 50%;
+    border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
+  }
 
-    &::before {
-      bottom: 0;
-      border-top-color: var(--#{$prefix}popover-arrow-border);
-    }
+  &::before {
+    bottom: 0;
+    border-top-color: var(--#{$prefix}popover-arrow-border);
+  }
 
-    &::after {
-      bottom: var(--#{$prefix}popover-border-width);
-      border-top-color: var(--#{$prefix}popover-bg);
-    }
+  &::after {
+    bottom: var(--#{$prefix}popover-border-width);
+    border-top-color: var(--#{$prefix}popover-bg);
   }
 }
 
-/* rtl:begin:ignore */
-.bs-popover-end {
-  > .popover-arrow {
-    left: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
-    width: var(--#{$prefix}popover-arrow-height);
-    height: var(--#{$prefix}popover-arrow-width);
-
-    &::before,
-    &::after {
-      border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
-    }
-
-    &::before {
-      left: 0;
-      border-right-color: var(--#{$prefix}popover-arrow-border);
-    }
-
-    &::after {
-      left: var(--#{$prefix}popover-border-width);
-      border-right-color: var(--#{$prefix}popover-bg);
-    }
+.popover[data-bs-placement="bottom"] {
+  &::before,
+  &::after {
+    left: 50%;
+    border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list
   }
-}
 
-/* rtl:end:ignore */
+  &::before {
+    top: 0;
+    border-bottom-color: var(--#{$prefix}popover-arrow-border);
+  }
 
-.bs-popover-bottom {
-  > .popover-arrow {
-    top: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
+  &::after {
+    top: var(--#{$prefix}popover-border-width);
+    border-bottom-color: var(--#{$prefix}popover-bg);
+  }
+}
 
-    &::before,
-    &::after {
-      border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list
-    }
 
-    &::before {
-      top: 0;
-      border-bottom-color: var(--#{$prefix}popover-arrow-border);
-    }
+/* rtl:begin:ignore */
 
-    &::after {
-      top: var(--#{$prefix}popover-border-width);
-      border-bottom-color: var(--#{$prefix}popover-bg);
-    }
+.popover[data-bs-placement="right"] {
+  &::before,
+  &::after {
+    top: 50%;
+    border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
+    transform: translateY(-50%);
   }
 
-  // This will remove the popover-header's border just below the arrow
-  .popover-header::before {
-    position: absolute;
-    top: 0;
-    left: 50%;
-    display: block;
-    width: var(--#{$prefix}popover-arrow-width);
-    margin-left: calc(var(--#{$prefix}popover-arrow-width) * -.5); // stylelint-disable-line function-disallowed-list
-    content: "";
-    border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg);
+  &::before {
+    left: 0;
+    border-right-color: var(--#{$prefix}popover-arrow-border);
   }
-}
 
-/* rtl:begin:ignore */
-.bs-popover-start {
-  > .popover-arrow {
-    right: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
-    width: var(--#{$prefix}popover-arrow-height);
-    height: var(--#{$prefix}popover-arrow-width);
-
-    &::before,
-    &::after {
-      border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list
-    }
-
-    &::before {
-      right: 0;
-      border-left-color: var(--#{$prefix}popover-arrow-border);
-    }
-
-    &::after {
-      right: var(--#{$prefix}popover-border-width);
-      border-left-color: var(--#{$prefix}popover-bg);
-    }
+  &::after {
+    left: var(--#{$prefix}popover-border-width);
+    border-right-color: var(--#{$prefix}popover-bg);
   }
 }
 
-/* rtl:end:ignore */
 
-.bs-popover-auto {
-  &[data-popper-placement^="top"] {
-    @extend .bs-popover-top;
+.popover[data-bs-placement="left"] {
+  &::before,
+  &::after {
+    top: 50%;
+    border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list
+    transform: translateY(-50%);
   }
-  &[data-popper-placement^="right"] {
-    @extend .bs-popover-end;
-  }
-  &[data-popper-placement^="bottom"] {
-    @extend .bs-popover-bottom;
+
+  &::before {
+    right: 0;
+    border-left-color: var(--#{$prefix}popover-arrow-border);
   }
-  &[data-popper-placement^="left"] {
-    @extend .bs-popover-start;
+
+  &::after {
+    right: var(--#{$prefix}popover-border-width);
+    border-left-color: var(--#{$prefix}popover-bg);
   }
 }
 
+
+/* rtl:end:ignore */
+
+// This will remove the popover-header's border just below the arrow
+.popover-header::before {
+  position: absolute;
+  top: 0;
+  left: 50%;
+  display: block;
+  width: var(--#{$prefix}popover-arrow-width);
+  margin-left: calc(var(--#{$prefix}popover-arrow-width) * -.5); // stylelint-disable-line function-disallowed-list
+  content: "";
+  border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg);
+}
+
+
 // Offset the popover to account for the popover arrow
 .popover-header {
   padding: var(--#{$prefix}popover-header-padding-y) var(--#{$prefix}popover-header-padding-x);
diff --git a/scss/_tooltip.scss b/scss/_tooltip.scss
index 7da3df3e00c6b0768d7f9960f7f346b1bde62310..8aae09528e1e53e91d7c9813a2dd907011d7af80 100644
--- a/scss/_tooltip.scss
+++ b/scss/_tooltip.scss
@@ -5,7 +5,6 @@
   --#{$prefix}tooltip-max-width: #{$tooltip-max-width};
   --#{$prefix}tooltip-padding-x: #{$tooltip-padding-x};
   --#{$prefix}tooltip-padding-y: #{$tooltip-padding-y};
-  --#{$prefix}tooltip-margin: #{$tooltip-margin};
   @include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size);
   --#{$prefix}tooltip-color: #{$tooltip-color};
   --#{$prefix}tooltip-bg: #{$tooltip-bg};
@@ -15,11 +14,12 @@
   --#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height};
   // scss-docs-end tooltip-css-vars
 
+  position: absolute;
+  top: 0;
+  left: 0;
   z-index: var(--#{$prefix}tooltip-zindex);
   display: block;
   padding: var(--#{$prefix}tooltip-arrow-height);
-  margin: var(--#{$prefix}tooltip-margin);
-  @include deprecate("`$tooltip-margin`", "v5", "v5.x", true);
   // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
   // So reset our font and text properties to avoid inheriting weird values.
   @include reset-text();
@@ -30,83 +30,44 @@
 
   &.show { opacity: var(--#{$prefix}tooltip-opacity); }
 
-  .tooltip-arrow {
-    display: block;
-    width: var(--#{$prefix}tooltip-arrow-width);
-    height: var(--#{$prefix}tooltip-arrow-height);
-
-    &::before {
-      position: absolute;
-      content: "";
-      border-color: transparent;
-      border-style: solid;
-    }
-  }
-}
-
-.bs-tooltip-top .tooltip-arrow {
-  bottom: 0;
-
   &::before {
-    top: -1px;
-    border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
-    border-top-color: var(--#{$prefix}tooltip-bg);
+    position: absolute;
+    content: "";
+    border-color: transparent;
+    border-style: solid;
+    transform: translateX(-50%);
   }
-}
-
-/* rtl:begin:ignore */
-.bs-tooltip-end .tooltip-arrow {
-  left: 0;
-  width: var(--#{$prefix}tooltip-arrow-height);
-  height: var(--#{$prefix}tooltip-arrow-width);
 
-  &::before {
-    right: -1px;
-    border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
-    border-right-color: var(--#{$prefix}tooltip-bg);
-  }
 }
 
-/* rtl:end:ignore */
+.tooltip[data-bs-placement="top"]::before {
+  bottom: 0;
+  left: 50%;
+  border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
+  border-top-color: var(--#{$prefix}tooltip-bg);
+}
 
-.bs-tooltip-bottom .tooltip-arrow {
+.tooltip[data-bs-placement="bottom"]::before {
   top: 0;
-
-  &::before {
-    bottom: -1px;
-    border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
-    border-bottom-color: var(--#{$prefix}tooltip-bg);
-  }
+  left: 50%;
+  border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
+  border-bottom-color: var(--#{$prefix}tooltip-bg);
 }
 
-/* rtl:begin:ignore */
-.bs-tooltip-start .tooltip-arrow {
-  right: 0;
-  width: var(--#{$prefix}tooltip-arrow-height);
-  height: var(--#{$prefix}tooltip-arrow-width);
-
-  &::before {
-    left: -1px;
-    border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
-    border-left-color: var(--#{$prefix}tooltip-bg);
-  }
+.tooltip[data-bs-placement="right"]::before {
+  top: 50%;
+  left: 0;
+  border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
+  border-right-color: var(--#{$prefix}tooltip-bg);
+  transform: translateY(-50%);
 }
 
-/* rtl:end:ignore */
-
-.bs-tooltip-auto {
-  &[data-popper-placement^="top"] {
-    @extend .bs-tooltip-top;
-  }
-  &[data-popper-placement^="right"] {
-    @extend .bs-tooltip-end;
-  }
-  &[data-popper-placement^="bottom"] {
-    @extend .bs-tooltip-bottom;
-  }
-  &[data-popper-placement^="left"] {
-    @extend .bs-tooltip-start;
-  }
+.tooltip[data-bs-placement="left"]::before {
+  top: 50%;
+  right: 0;
+  border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
+  border-left-color: var(--#{$prefix}tooltip-bg);
+  transform: translateY(-50%);
 }
 
 // Wrapper for the tooltip content
diff --git a/scss/_variables.scss b/scss/_variables.scss
index 82d33b0baf127101e2ef5012b9763dfaf5b086fa..0013865cdc50398a3bf2ee82bb145e005b5b0aaf 100644
--- a/scss/_variables.scss
+++ b/scss/_variables.scss
@@ -1299,7 +1299,6 @@ $tooltip-border-radius:             $border-radius !default;
 $tooltip-opacity:                   .9 !default;
 $tooltip-padding-y:                 $spacer * .25 !default;
 $tooltip-padding-x:                 $spacer * .5 !default;
-$tooltip-margin:                    null !default; // TODO: remove this in v6
 
 $tooltip-arrow-width:               .8rem !default;
 $tooltip-arrow-height:              .4rem !default;
diff --git a/site/assets/js/snippets.js b/site/assets/js/snippets.js
index 53f8a786ec6fd286f3b9bdd3be9c428c992d44c0..075c5e50ce13a34e98c68b4591712cd302e71bc0 100644
--- a/site/assets/js/snippets.js
+++ b/site/assets/js/snippets.js
@@ -23,7 +23,7 @@
   // Instantiate all tooltips in a docs or StackBlitz page
   document.querySelectorAll('[data-bs-toggle="tooltip"]')
     .forEach(tooltip => {
-      new bootstrap.Tooltip(tooltip)
+      new bootstrap.Tooltip(tooltip, { trigger: 'click' })
     })
 
   // --------
diff --git a/site/content/docs/5.2/components/dropdowns.md b/site/content/docs/5.2/components/dropdowns.md
index ec7e584b5b5081600b0d2cf1331f7938ebb9a6de..7eb31bbe2fd07bf2b23daccb648ab176cd1ac9cd 100644
--- a/site/content/docs/5.2/components/dropdowns.md
+++ b/site/content/docs/5.2/components/dropdowns.md
@@ -10,7 +10,7 @@ toc: true
 
 Dropdowns are toggleable, contextual overlays for displaying lists of links and more. They're made interactive with the included Bootstrap dropdown JavaScript plugin. They're toggled by clicking, not by hovering; this is [an intentional design decision](https://markdotto.com/2012/02/27/bootstrap-explained-dropdowns/).
 
-Dropdowns are built on a third party library, [Popper](https://popper.js.org/), which provides dynamic positioning and viewport detection. Be sure to include [popper.min.js]({{< param "cdn.popper" >}}) before Bootstrap's JavaScript or use `bootstrap.bundle.min.js` / `bootstrap.bundle.js` which contains Popper. Popper isn't used to position dropdowns in navbars though as dynamic positioning isn't required.
+Dropdowns are built on a third party library, [Popper](https://popper.js.org/), which provides dynamic positioning and viewport detection. Be sure to include [popper.min.js]({{< param "cdn.floating_ui" >}}) before Bootstrap's JavaScript or use `bootstrap.bundle.min.js` / `bootstrap.bundle.js` which contains Popper. Popper isn't used to position dropdowns in navbars though as dynamic positioning isn't required.
 
 ## Accessibility
 
diff --git a/site/content/docs/5.2/components/popovers.md b/site/content/docs/5.2/components/popovers.md
index 87e756434be240fc991ef964639c75e78ed8adba..82953bd9eb4271006c202b2060d5481ee677a60b 100644
--- a/site/content/docs/5.2/components/popovers.md
+++ b/site/content/docs/5.2/components/popovers.md
@@ -10,7 +10,7 @@ toc: true
 
 Things to know when using the popover plugin:
 
-- Popovers rely on the third party library [Popper](https://popper.js.org/) for positioning. You must include [popper.min.js]({{< param "cdn.popper" >}}) before `bootstrap.js`, or use one `bootstrap.bundle.min.js` which contains Popper.
+- Popovers rely on the third party library [Popper](https://popper.js.org/) for positioning. You must include [popper.min.js]({{< param "cdn.floating_ui" >}}) before `bootstrap.js`, or use one `bootstrap.bundle.min.js` which contains Popper.
 - Popovers require the [popover plugin]({{< docsref "/components/popovers" >}}) as a dependency.
 - Popovers are opt-in for performance reasons, so **you must initialize them yourself**.
 - Zero-length `title` and `content` values will never show a popover.
diff --git a/site/content/docs/5.2/components/tooltips.md b/site/content/docs/5.2/components/tooltips.md
index 9f1bbdc8daf63c1330ee3b549ca80bf6bee12e79..2c78820d8d04351679692fcf7d88dd332a536d2b 100644
--- a/site/content/docs/5.2/components/tooltips.md
+++ b/site/content/docs/5.2/components/tooltips.md
@@ -10,7 +10,7 @@ toc: true
 
 Things to know when using the tooltip plugin:
 
-- Tooltips rely on the third party library [Popper](https://popper.js.org/) for positioning. You must include [popper.min.js]({{< param "cdn.popper" >}}) before `bootstrap.js`, or use one `bootstrap.bundle.min.js` which contains Popper.
+- Tooltips rely on the third party library [Popper](https://popper.js.org/) for positioning. You must include [popper.min.js]({{< param "cdn.floating_ui" >}}) before `bootstrap.js`, or use one `bootstrap.bundle.min.js` which contains Popper.
 - Tooltips are opt-in for performance reasons, so **you must initialize them yourself**.
 - Tooltips with zero-length titles are never displayed.
 - Specify `container: 'body'` to avoid rendering problems in more complex components (like our input groups, button groups, etc).
diff --git a/site/content/docs/5.2/getting-started/download.md b/site/content/docs/5.2/getting-started/download.md
index eeffdc83e5c779cc6636cd26e2d8a60e0d50eaa4..32a75f7c6059dd48781098f2420915e6d4678d37 100644
--- a/site/content/docs/5.2/getting-started/download.md
+++ b/site/content/docs/5.2/getting-started/download.md
@@ -46,7 +46,7 @@ Skip the download with [jsDelivr](https://www.jsdelivr.com/) to deliver cached v
 If you're using our compiled JavaScript and prefer to include Popper separately, add Popper before our JS, via a CDN preferably.
 
 ```html
-<script src="{{< param "cdn.popper" >}}" integrity="{{< param "cdn.popper_hash" >}}" crossorigin="anonymous"></script>
+<script src="{{< param "cdn.floating_ui" >}}" integrity="{{< param "cdn.floating_ui_hash" >}}" crossorigin="anonymous"></script>
 <script src="{{< param "cdn.js" >}}" integrity="{{< param "cdn.js_hash" >}}" crossorigin="anonymous"></script>
 ```
 
diff --git a/site/content/docs/5.2/getting-started/introduction.md b/site/content/docs/5.2/getting-started/introduction.md
index 579e04b2f4109fc3f337f2d268bb0c366a6bde64..096e5330378556bc56523585392daee99dd4f2ba 100644
--- a/site/content/docs/5.2/getting-started/introduction.md
+++ b/site/content/docs/5.2/getting-started/introduction.md
@@ -53,7 +53,7 @@ Get started by including Bootstrap's production-ready CSS and JavaScript via CDN
    You can also include [Popper](https://popper.js.org/) and our JS separately. If you don't plan to use dropdowns, popovers, or tooltips, save some kilobytes by not including Popper.
 
    ```html
-   <script src="{{< param "cdn.popper" >}}" integrity="{{< param "cdn.popper_hash" >}}" crossorigin="anonymous"></script>
+   <script src="{{< param "cdn.floating_ui" >}}" integrity="{{< param "cdn.floating_ui_hash" >}}" crossorigin="anonymous"></script>
    <script src="{{< param "cdn.js" >}}" integrity="{{< param "cdn.js_hash" >}}" crossorigin="anonymous"></script>
    ```
 
diff --git a/site/content/docs/5.2/getting-started/javascript.md b/site/content/docs/5.2/getting-started/javascript.md
index fa157e006c18b76e56e8d9c69624421d227b2cf4..48a1e3114880c2e473ac990ac306be5a4ee3a0f9 100644
--- a/site/content/docs/5.2/getting-started/javascript.md
+++ b/site/content/docs/5.2/getting-started/javascript.md
@@ -71,7 +71,7 @@ To fix this, you can use an `importmap` to resolve the arbitrary module names to
     <script type="importmap">
     {
       "imports": {
-        "@popperjs/core": "{{< param "cdn.popper" >}}",
+        "@popperjs/core": "{{< param "cdn.floating_ui" >}}",
         "bootstrap": "https://cdn.jsdelivr.net/npm/bootstrap@{{< param "current_version" >}}/dist/js/bootstrap.esm.min.js"
       }
     }
diff --git a/site/content/docs/5.2/getting-started/rtl.md b/site/content/docs/5.2/getting-started/rtl.md
index f4abf050baee7e814cc8cca6dd1c7e9f239314e7..9511e71fb4f0cf7fb60d79ff35e29f9f3cb563a8 100644
--- a/site/content/docs/5.2/getting-started/rtl.md
+++ b/site/content/docs/5.2/getting-started/rtl.md
@@ -58,7 +58,7 @@ You can see the above requirements reflected in this modified RTL starter templa
 
     <!-- Option 2: Separate Popper and Bootstrap JS -->
     <!--
-    <script src="{{< param "cdn.popper" >}}" integrity="{{< param "cdn.popper_hash" >}}" crossorigin="anonymous"></script>
+    <script src="{{< param "cdn.floating_ui" >}}" integrity="{{< param "cdn.floating_ui_hash" >}}" crossorigin="anonymous"></script>
     <script src="{{< param "cdn.js" >}}" integrity="{{< param "cdn.js_hash" >}}" crossorigin="anonymous"></script>
     -->
   </body>