diff --git a/js/src/tooltip.ts b/js/src/tooltip.ts index ec327e74b3ab..98bc6c81f38b 100644 --- a/js/src/tooltip.ts +++ b/js/src/tooltip.ts @@ -933,6 +933,14 @@ class Tooltip extends BaseComponent { } } + if (this._element.getAttribute('data-bs-title') !== null) { + dataAttributes.title = this._element.getAttribute('data-bs-title') + } + + if (this._element.getAttribute('data-bs-content') !== null) { + dataAttributes.content = this._element.getAttribute('data-bs-content') + } + config = { ...dataAttributes, ...(typeof config === 'object' && config ? config : {}) @@ -961,11 +969,15 @@ class Tooltip extends BaseComponent { // Coerce number/boolean title and content to strings. `data-bs-title="true"` // / `data-bs-content="false"` are auto-converted to booleans by the data-API, // which would otherwise fail the (null|string|element|function) type check. - if (typeof config.title === 'number' || typeof config.title === 'boolean') { + if (config.title === null) { + config.title = '' + } else if (typeof config.title === 'number' || typeof config.title === 'boolean') { config.title = config.title.toString() } - if (typeof config.content === 'number' || typeof config.content === 'boolean') { + if (config.content === null) { + config.content = '' + } else if (typeof config.content === 'number' || typeof config.content === 'boolean') { config.content = config.content.toString() } diff --git a/js/tests/unit/tooltip.spec.js b/js/tests/unit/tooltip.spec.js index b37f7fb274da..eb039bbdd3e3 100644 --- a/js/tests/unit/tooltip.spec.js +++ b/js/tests/unit/tooltip.spec.js @@ -100,6 +100,16 @@ describe('Tooltip', () => { expect(tooltip._config.content).toEqual('false') }) + it('should preserve raw strings without reformatting numbers or throwing on empty title/content', () => { + fixtureEl.innerHTML = '' + + const tooltipEl = fixtureEl.querySelector('a') + const tooltip = new Tooltip(tooltipEl) + + expect(tooltip._config.title).toEqual('9.90') + expect(tooltip._config.content).toEqual('') + }) + it('should enable selector delegation', () => { return new Promise(resolve => { fixtureEl.innerHTML = '
'