twbs/bootstrap · error · TypeError

Bootstrap's tooltips require Popper (https://popper.js.org/d

Error message

Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)

What it means

Tooltip's constructor checks the Popper namespace before calling super() and throws immediately — so new bootstrap.Tooltip(el) or Tooltip.getOrCreateInstance(el) itself fails, unlike Dropdown which only fails when the menu opens. It means @popperjs/core is absent at runtime: the standalone UMD build (dist/js/bootstrap.js) keeps Popper external and expects a window.Popper global, so a missing script, a CDN failure, or an externalized bundler config triggers it. Bundle builds (bootstrap.bundle.js) and npm/ESM usage include Popper and are immune.

Source

Thrown at js/src/tooltip.js:108

  offset: '(array|string|function)',
  placement: '(string|function)',
  popperConfig: '(null|object|function)',
  sanitize: 'boolean',
  sanitizeFn: '(null|function)',
  selector: '(string|boolean)',
  template: 'string',
  title: '(string|element|function)',
  trigger: 'string'
}

/**
 * Class definition
 */

class Tooltip extends BaseComponent {
  constructor(element, config) {
    if (typeof Popper === 'undefined') {
      throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org/docs/v2/)')
    }

    super(element, config)

    // Private
    this._isEnabled = true
    this._timeout = 0
    this._isHovered = null
    this._activeTrigger = {}
    this._popper = null
    this._templateFactory = null
    this._newContent = null

    // Protected
    this.tip = null

    this._setListeners()

View on GitHub (pinned to 6177d5f849)

Solutions

  1. Switch to the bundle build that contains Popper: dist/js/bootstrap.bundle(.min).js.
  2. Or load Popper's UMD build before bootstrap.js: <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2/dist/umd/popper.min.js"></script>.
  3. With npm, import { Tooltip } from 'bootstrap' so the bundler resolves @popperjs/core.
  4. Verify in the Network tab that the Popper script actually loads on the failing page.

Example fix

<!-- before: UMD build, Popper never loaded -->
<script src="bootstrap.min.js"></script>
<script>new bootstrap.Tooltip(document.querySelector('[data-bs-toggle="tooltip"]'))</script>
<!-- TypeError: Bootstrap's tooltips require Popper -->

<!-- after, option A: bundle containing Popper -->
<script src="bootstrap.bundle.min.js"></script>

<!-- after, option B: Popper before bootstrap -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2/dist/umd/popper.min.js"></script>
<script src="bootstrap.min.js"></script>
Defensive patterns

Strategy: validation

Validate before calling

function ensurePopper() {
  if (typeof window !== 'undefined' && typeof window.Popper === 'undefined') {
    throw new Error('Popper is missing — load bootstrap.bundle.js or @popperjs/core UMD before bootstrap.js')
  }
}
ensurePopper()
bootstrap.Tooltip.getOrCreateInstance(el)

Try / catch

try {
  bootstrap.Tooltip.getOrCreateInstance(el)
} catch (err) {
  if (err instanceof TypeError && /require Popper/.test(err.message)) {
    // skip tooltip init or dynamically load popper, then retry init once
  } else {
    throw err
  }
}

Prevention

When it happens

Trigger: new bootstrap.Tooltip(el) or tooltip tooltip() init with dist/js/bootstrap.js loaded but no @popperjs/core script; a Popper CDN request blocked or 404-ing while bootstrap.js loads from cache; a custom Rollup/webpack build treating '@popperjs/core' as external for UMD output; jsdom tests that never load the Popper script.

Common situations: Pages initialized with $('...').tooltip() or data-bs-toggle="tooltip" after a CDN change; ad blockers removing popper.js URLs; offline development; template layouts that conditionally load bootstrap but always load popper's slot empty.

Related errors


AI-assisted analysis of twbs/bootstrap@6177d5f849 (2026-08-22). Data as JSON: /api/errors/2613411ff3e1da76. Report an issue: GitHub.