2
0
mirror of https://github.com/tenrok/bootstrap.git synced 2026-05-15 11:59:39 +03:00

Merge branch 'main' into examples-navbar-centered

This commit is contained in:
XhmikosR
2022-07-11 11:31:46 +03:00
committed by GitHub
64 changed files with 2263 additions and 3088 deletions
+2
View File
@@ -91,7 +91,9 @@
"scrollspy",
"Segoe",
"semibold",
"socio",
"srcset",
"stackblitz",
"stickied",
"Stylelint",
"subnav",
+1 -1
View File
@@ -69,7 +69,7 @@ Guidelines for bug reports:
3. **Isolate the problem** — ideally create a [reduced test
case](https://css-tricks.com/reduced-test-cases/) and a live example.
[This JS Bin](https://jsbin.com/lolome/edit?html,output) is a helpful template.
These [v4 CodePen](https://codepen.io/team/bootstrap/pen/yLabNQL) and [v5 CodePen](https://codepen.io/team/bootstrap/pen/qBamdLj) are helpful templates.
A good bug report shouldn't leave others needing to chase you up for more
+2 -2
View File
@@ -10,10 +10,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: awaiting reply
if: github.event.label.name == 'awaiting-reply'
if: github.event.label.name == 'needs-example'
uses: actions-cool/issues-helper@v3
with:
actions: "create-comment"
token: ${{ secrets.GITHUB_TOKEN }}
body: |
Hello @${{ github.event.issue.user.login }}. Bug reports must include a **live demo** of the issue. Per our [contributing guidelines](https://github.com/twbs/bootstrap/blob/main/.github/CONTRIBUTING.md), please create a reduced test case on [CodePen](https://codepen.io/) or [JS Bin](https://jsbin.com/) and report back with your link, Bootstrap version, and specific browser and Operating System details.
Hello @${{ github.event.issue.user.login }}. Bug reports must include a **live demo** of the issue. Per our [contributing guidelines](https://github.com/twbs/bootstrap/blob/main/.github/CONTRIBUTING.md), please create a reduced test case on [CodePen](https://codepen.io/) or [StackBlitz](https://stackblitz.com/) and report back with your link, Bootstrap version, and specific browser and Operating System details.
+109 -20
View File
@@ -2,42 +2,131 @@
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
Examples of behavior that contributes to a positive environment for our
community include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior by participants include:
Examples of unacceptable behavior include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
## Enforcement Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at mdo@getbootstrap.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
mdo@getbootstrap.com.
All complaints will be reviewed and investigated promptly and fairly.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 1.4, available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct/>
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
+1 -1
View File
@@ -78,7 +78,7 @@ const Default = {
}
const DefaultType = {
interval: '(number|boolean)',
interval: '(number|boolean)', // TODO:v6 remove boolean support
keyboard: 'boolean',
pause: '(string|boolean)',
ride: '(boolean|string)',
+13 -8
View File
@@ -89,7 +89,7 @@ function getElementEvents(element) {
function bootstrapHandler(element, fn) {
return function handler(event) {
event.delegateTarget = element
hydrateObj(event, { delegateTarget: element })
if (handler.oneOff) {
EventHandler.off(element, event.type, fn)
@@ -109,7 +109,7 @@ function bootstrapDelegationHandler(element, selector, fn) {
continue
}
event.delegateTarget = target
hydrateObj(event, { delegateTarget: target })
if (handler.oneOff) {
EventHandler.off(element, event.type, selector, fn)
@@ -234,7 +234,7 @@ const EventHandler = {
if (typeof callable !== 'undefined') {
// Simplest case: handler is passed, remove that listener ONLY.
if (!storeElementEvent) {
if (!Object.keys(storeElementEvent).length) {
return
}
@@ -302,11 +302,16 @@ const EventHandler = {
function hydrateObj(obj, meta) {
for (const [key, value] of Object.entries(meta || {})) {
Object.defineProperty(obj, key, {
get() {
return value
}
})
try {
obj[key] = value
} catch {
Object.defineProperty(obj, key, {
configurable: true,
get() {
return value
}
})
}
}
return obj
+2 -2
View File
@@ -30,7 +30,7 @@ const EVENT_HIDDEN = `hidden${EVENT_KEY}`
const EVENT_SHOW = `show${EVENT_KEY}`
const EVENT_SHOWN = `shown${EVENT_KEY}`
const EVENT_RESIZE = `resize${EVENT_KEY}`
const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`
const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`
const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
@@ -221,7 +221,7 @@ class Modal extends BaseComponent {
}
})
EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => {
EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {
if (event.target !== event.currentTarget) { // click is inside modal-dialog
return
}
+1 -1
View File
@@ -128,7 +128,7 @@ class ScrollSpy extends BaseComponent {
const root = this._rootElement || window
const height = observableSection.offsetTop - this._element.offsetTop
if (root.scrollTo) {
root.scrollTo({ top: height })
root.scrollTo({ top: height, behavior: 'smooth' })
return
}
+4 -12
View File
@@ -109,13 +109,9 @@ class Tab extends BaseComponent {
this._activate(getElementFromSelector(element)) // Search and activate/show the proper section
const isAnimated = element.classList.contains(CLASS_NAME_FADE)
const complete = () => {
if (isAnimated) { // todo: maybe is redundant
element.classList.add(CLASS_NAME_SHOW)
}
if (element.getAttribute('role') !== 'tab') {
element.classList.add(CLASS_NAME_SHOW)
return
}
@@ -128,7 +124,7 @@ class Tab extends BaseComponent {
})
}
this._queueCallback(complete, element, isAnimated)
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
}
_deactivate(element, relatedElem) {
@@ -141,13 +137,9 @@ class Tab extends BaseComponent {
this._deactivate(getElementFromSelector(element)) // Search and deactivate the shown section too
const isAnimated = element.classList.contains(CLASS_NAME_FADE)
const complete = () => {
if (isAnimated) { // todo maybe is redundant
element.classList.remove(CLASS_NAME_SHOW)
}
if (element.getAttribute('role') !== 'tab') {
element.classList.remove(CLASS_NAME_SHOW)
return
}
@@ -157,7 +149,7 @@ class Tab extends BaseComponent {
EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })
}
this._queueCallback(complete, element, isAnimated)
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
}
_keydown(event) {
+15 -15
View File
@@ -115,6 +115,7 @@ class Tooltip extends BaseComponent {
this._activeTrigger = {}
this._popper = null
this._templateFactory = null
this._newContent = null
// Protected
this.tip = null
@@ -205,6 +206,12 @@ class Tooltip extends BaseComponent {
return
}
// todo v6 remove this OR make it optional
if (this.tip) {
this.tip.remove()
this.tip = null
}
const tip = this._getTipElement()
this._element.setAttribute('aria-describedby', tip.getAttribute('id'))
@@ -219,7 +226,7 @@ class Tooltip extends BaseComponent {
if (this._popper) {
this._popper.update()
} else {
this._createPopper(tip)
this._popper = this._createPopper(tip)
}
tip.classList.add(CLASS_NAME_SHOW)
@@ -305,7 +312,7 @@ class Tooltip extends BaseComponent {
_getTipElement() {
if (!this.tip) {
this.tip = this._createTipElement(this._getContentForTemplate())
this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())
}
return this.tip
@@ -335,17 +342,11 @@ class Tooltip extends BaseComponent {
}
setContent(content) {
let isShown = false
if (this.tip) {
isShown = this._isShown()
this._newContent = content
if (this._isShown()) {
this.tip.remove()
this.tip = null
}
this._disposePopper()
this.tip = this._createTipElement(content)
if (isShown) {
this._disposePopper()
this.show()
}
}
@@ -373,7 +374,7 @@ class Tooltip extends BaseComponent {
}
_getTitle() {
return this._config.title
return this._resolvePossibleFunction(this._config.title) || this._config.originalTitle
}
// Private
@@ -394,7 +395,7 @@ class Tooltip extends BaseComponent {
this._config.placement.call(this, tip, this._element) :
this._config.placement
const attachment = AttachmentMap[placement.toUpperCase()]
this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))
return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))
}
_getOffset() {
@@ -517,7 +518,7 @@ class Tooltip extends BaseComponent {
return
}
if (!this._element.getAttribute('aria-label') && !this._element.textContent) {
if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {
this._element.setAttribute('aria-label', title)
}
@@ -592,7 +593,6 @@ class Tooltip extends BaseComponent {
}
config.originalTitle = this._element.getAttribute('title') || ''
config.title = this._resolvePossibleFunction(config.title) || config.originalTitle
if (typeof config.title === 'number') {
config.title = config.title.toString()
}
+7 -7
View File
@@ -406,7 +406,7 @@ describe('Carousel', () => {
Simulator.setType('pointer')
fixtureEl.innerHTML = [
'<div class="carousel" data-bs-interval="false">',
'<div class="carousel">',
' <div class="carousel-inner">',
' <div id="item" class="carousel-item">',
' <img alt="">',
@@ -453,7 +453,7 @@ describe('Carousel', () => {
Simulator.setType('pointer')
fixtureEl.innerHTML = [
'<div class="carousel" data-bs-interval="false">',
'<div class="carousel">',
' <div class="carousel-inner">',
' <div id="item" class="carousel-item active">',
' <img alt="">',
@@ -495,7 +495,7 @@ describe('Carousel', () => {
document.documentElement.ontouchstart = noop
fixtureEl.innerHTML = [
'<div class="carousel" data-bs-interval="false">',
'<div class="carousel">',
' <div class="carousel-inner">',
' <div id="item" class="carousel-item">',
' <img alt="">',
@@ -536,7 +536,7 @@ describe('Carousel', () => {
document.documentElement.ontouchstart = noop
fixtureEl.innerHTML = [
'<div class="carousel" data-bs-interval="false">',
'<div class="carousel">',
' <div class="carousel-inner">',
' <div id="item" class="carousel-item active">',
' <img alt="">',
@@ -578,7 +578,7 @@ describe('Carousel', () => {
document.documentElement.ontouchstart = noop
fixtureEl.innerHTML = [
'<div class="carousel" data-bs-interval="false">',
'<div class="carousel">',
' <div class="carousel-inner">',
' <div id="item" class="carousel-item active">',
' <img alt="">',
@@ -622,7 +622,7 @@ describe('Carousel', () => {
clearPointerEvents()
document.documentElement.ontouchstart = noop
fixtureEl.innerHTML = '<div class="carousel" data-bs-interval="false"></div>'
fixtureEl.innerHTML = '<div class="carousel"></div>'
const carouselEl = fixtureEl.querySelector('.carousel')
const carousel = new Carousel(carouselEl)
@@ -910,7 +910,7 @@ describe('Carousel', () => {
it('should not call next when the page is not visible', () => {
fixtureEl.innerHTML = [
'<div style="display: none;">',
' <div class="carousel" data-bs-interval="false"></div>',
' <div class="carousel"></div>',
'</div>'
].join('')
+37
View File
@@ -441,4 +441,41 @@ describe('EventHandler', () => {
expect(i).toEqual(5)
})
})
describe('general functionality', () => {
it('should hydrate properties, and make them configurable', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div id="div1">',
' <div id="div2"></div>',
' <div id="div3"></div>',
'</div>'
].join('')
const div1 = fixtureEl.querySelector('#div1')
const div2 = fixtureEl.querySelector('#div2')
const div3 = fixtureEl.querySelector('#div3')
EventHandler.on(div1, 'click', event => {
event.originalTarget = div3
expect(event.currentTarget).toBe(div2)
Object.defineProperty(event, 'currentTarget', {
configurable: true,
get() {
return div1
}
})
expect(event.currentTarget).toBe(div1)
resolve()
})
expect(() => {
EventHandler.trigger(div1, 'click', { delegateTarget: div2, originalTarget: null, currentTarget: div2 })
}).not.toThrowError(TypeError)
})
})
})
})
+1 -1
View File
@@ -166,7 +166,7 @@ describe('SelectorEngine', () => {
'<span>lorem</span>',
'<a>lorem</a>',
'<button>lorem</button>',
'<input />',
'<input>',
'<textarea></textarea>',
'<select></select>',
'<details>lorem</details>'
+1 -1
View File
@@ -986,7 +986,7 @@ describe('Dropdown', () => {
'<div class="dropdown">',
' <button class="btn dropdown-toggle" data-bs-toggle="dropdown">Dropdown</button>',
' <div class="dropdown-menu">',
' <a class="dropdown-item" href="#">Dropdwon item</a>',
' <a class="dropdown-item" href="#">Dropdown item</a>',
' </div>',
'</div>'
].join('')
+14 -7
View File
@@ -641,9 +641,10 @@ describe('Modal', () => {
modalEl.addEventListener('shown.bs.modal', () => {
const spy = spyOn(modal, '_queueCallback').and.callThrough()
const mouseDown = createEvent('mousedown')
modalEl.click()
modalEl.click()
modalEl.dispatchEvent(mouseDown)
modalEl.dispatchEvent(mouseDown)
setTimeout(() => {
expect(spy).toHaveBeenCalledTimes(1)
@@ -709,13 +710,19 @@ describe('Modal', () => {
fixtureEl.innerHTML = '<div class="modal"><div class="modal-dialog"></div></div>'
const modalEl = fixtureEl.querySelector('.modal')
const dialogEl = modalEl.querySelector('.modal-dialog')
const modal = new Modal(modalEl)
modalEl.addEventListener('shown.bs.modal', () => {
modalEl.click()
})
modalEl.addEventListener('hidden.bs.modal', () => {
expect(document.querySelector('.modal-backdrop')).toBeNull()
spyOn(modal, 'hide')
modalEl.addEventListener('shown.bs.modal', () => {
const mouseDown = createEvent('mousedown')
dialogEl.dispatchEvent(mouseDown)
expect(modal.hide).not.toHaveBeenCalled()
modalEl.dispatchEvent(mouseDown)
expect(modal.hide).toHaveBeenCalled()
resolve()
})
+1 -1
View File
@@ -603,7 +603,7 @@ describe('Offcanvas', () => {
it('should not prevent event for input', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<input type="checkbox" data-bs-toggle="offcanvas" data-bs-target="#offcanvasdiv1" />',
'<input type="checkbox" data-bs-toggle="offcanvas" data-bs-target="#offcanvasdiv1">',
'<div id="offcanvasdiv1" class="offcanvas"></div>'
].join('')
+1 -1
View File
@@ -889,7 +889,7 @@ describe('ScrollSpy', () => {
setTimeout(() => {
if (div.scrollTo) {
expect(clickSpy).toHaveBeenCalledWith({ top: observable.offsetTop - div.offsetTop })
expect(clickSpy).toHaveBeenCalledWith({ top: observable.offsetTop - div.offsetTop, behavior: 'smooth' })
} else {
expect(clickSpy).toHaveBeenCalledWith(observable.offsetTop - div.offsetTop)
}
+2 -2
View File
@@ -904,7 +904,7 @@ describe('Tab', () => {
})
})
it('should not add `show` class to tab panes if there is no `.fade` class', () => {
it('should add `show` class to tab panes if there is no `.fade` class', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<ul class="nav nav-tabs" role="tablist">',
@@ -924,7 +924,7 @@ describe('Tab', () => {
const secondNavEl = fixtureEl.querySelector('#secondNav')
secondNavEl.addEventListener('shown.bs.tab', () => {
expect(fixtureEl.querySelectorAll('.show')).toHaveSize(0)
expect(fixtureEl.querySelectorAll('.tab-content .show')).toHaveSize(1)
resolve()
})
+23 -2
View File
@@ -185,7 +185,7 @@ describe('Tooltip', () => {
const tooltipEl = fixtureEl.querySelector('a')
const tooltip = new Tooltip(tooltipEl)
expect(tooltip._config.title).toEqual('Another tooltip')
expect(tooltip._getTitle()).toEqual('Another tooltip')
})
})
@@ -848,7 +848,7 @@ describe('Tooltip', () => {
}, 100)
setTimeout(() => {
expect(insertedFunc).toHaveBeenCalledTimes(1)
expect(insertedFunc).toHaveBeenCalledTimes(2)
resolve()
}, 200)
}, 0)
@@ -1166,6 +1166,7 @@ describe('Tooltip', () => {
tooltip.setContent({ '.tooltip-inner': 'foo' })
expect(tip()).not.toHaveClass('show')
tooltip.show()
expect(tip().querySelector('.tooltip-inner').textContent).toEqual('foo')
})
@@ -1229,6 +1230,7 @@ describe('Tooltip', () => {
})
tooltip.setContent({ '.tooltip': { 0: childContent, jquery: 'jQuery' } })
tooltip.show()
expect(childContent.parentNode).toEqual(tooltip._getTipElement())
})
@@ -1356,6 +1358,25 @@ describe('Tooltip', () => {
})
})
it('should add the aria-label attribute when element text content is a whitespace string', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="A tooltip"><span> </span></a>'
const tooltipEl = fixtureEl.querySelector('a')
const tooltip = new Tooltip(tooltipEl)
tooltipEl.addEventListener('shown.bs.tooltip', () => {
const tooltipShown = document.querySelector('.tooltip')
expect(tooltipShown).not.toBeNull()
expect(tooltipEl.getAttribute('aria-label')).toEqual('A tooltip')
resolve()
})
tooltip.show()
})
})
it('should not add the aria-label attribute if the attribute already exists', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = '<a href="#" rel="tooltip" aria-label="Different label" title="Another tooltip"></a>'
+3 -3
View File
@@ -425,8 +425,8 @@ describe('Util', () => {
it('should return true if the element has disabled attribute', () => {
fixtureEl.innerHTML = [
'<div>',
' <input id="input" disabled="disabled"/>',
' <input id="input1" disabled="disabled"/>',
' <input id="input" disabled="disabled">',
' <input id="input1" disabled="disabled">',
' <button id="button" disabled="true"></button>',
' <button id="button1" disabled="disabled"></button>',
' <button id="button2" disabled></button>',
@@ -460,7 +460,7 @@ describe('Util', () => {
it('should return true if the element has class "disabled" but disabled attribute is false', () => {
fixtureEl.innerHTML = [
'<div>',
' <input id="input" class="disabled" disabled="false"/>',
' <input id="input" class="disabled" disabled="false">',
'</div>'
].join('')
+1601 -2692
View File
File diff suppressed because it is too large Load Diff
+16 -16
View File
@@ -104,19 +104,19 @@
"@popperjs/core": "^2.11.5"
},
"devDependencies": {
"@babel/cli": "^7.17.10",
"@babel/core": "^7.18.2",
"@babel/preset-env": "^7.18.2",
"@babel/cli": "^7.18.6",
"@babel/core": "^7.18.6",
"@babel/preset-env": "^7.18.6",
"@popperjs/core": "^2.11.5",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-commonjs": "^22.0.0",
"@rollup/plugin-commonjs": "^22.0.1",
"@rollup/plugin-node-resolve": "^13.3.0",
"@rollup/plugin-replace": "^4.0.0",
"autoprefixer": "^10.4.7",
"bundlewatch": "^0.3.3",
"clean-css-cli": "^5.6.0",
"cross-env": "^7.0.3",
"eslint": "^8.16.0",
"eslint": "^8.19.0",
"eslint-config-xo": "^0.41.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-markdown": "^2.2.1",
@@ -124,31 +124,31 @@
"find-unused-sass-variables": "^4.0.4",
"globby": "^11.1.0",
"hammer-simulator": "0.0.1",
"hugo-bin": "^0.88.1",
"hugo-bin": "^0.89.0",
"ip": "^2.0.0",
"jquery": "^3.6.0",
"karma": "^6.3.20",
"karma": "^6.4.0",
"karma-browserstack-launcher": "1.4.0",
"karma-chrome-launcher": "^3.1.1",
"karma-coverage-istanbul-reporter": "^3.0.3",
"karma-detect-browsers": "^2.3.3",
"karma-firefox-launcher": "^2.1.2",
"karma-jasmine": "^5.0.1",
"karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"karma-rollup-preprocessor": "7.0.7",
"lockfile-lint": "^4.7.4",
"nodemon": "^2.0.16",
"lockfile-lint": "^4.7.6",
"nodemon": "^2.0.19",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.14",
"postcss-cli": "^9.1.0",
"rollup": "^2.75.5",
"postcss-cli": "^10.0.0",
"rollup": "^2.76.0",
"rollup-plugin-istanbul": "^3.0.0",
"rtlcss": "^3.5.0",
"sass": "^1.52.1",
"sass": "^1.53.0",
"shelljs": "^0.8.5",
"stylelint": "^14.8.5",
"stylelint-config-twbs-bootstrap": "^3.2.0",
"terser": "^5.14.0",
"stylelint": "^14.9.1",
"stylelint-config-twbs-bootstrap": "^4.0.0",
"terser": "^5.14.1",
"vnu-jar": "21.10.12"
},
"files": [
+1 -1
View File
@@ -22,7 +22,7 @@
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: var(--#{$prefix}badge-border-radius, 0); // stylelint-disable-line property-disallowed-list
@include border-radius(var(--#{$prefix}badge-border-radius));
@include gradient-bg();
// Empty badges collapse automatically
+21 -1
View File
@@ -103,7 +103,27 @@
// scss-docs-start btn-variant-loops
@each $color, $value in $theme-colors {
.btn-#{$color} {
@include button-variant($value, $value);
@if $color == "light" {
@include button-variant(
$value,
$value,
$hover-background: shade-color($value, $btn-hover-bg-shade-amount),
$hover-border: shade-color($value, $btn-hover-border-shade-amount),
$active-background: shade-color($value, $btn-active-bg-shade-amount),
$active-border: shade-color($value, $btn-active-border-shade-amount)
);
} @else if $color == "dark" {
@include button-variant(
$value,
$value,
$hover-background: tint-color($value, $btn-hover-bg-tint-amount),
$hover-border: tint-color($value, $btn-hover-border-tint-amount),
$active-background: tint-color($value, $btn-active-bg-tint-amount),
$active-border: tint-color($value, $btn-active-border-tint-amount)
);
} @else {
@include button-variant($value, $value);
}
}
}
+2
View File
@@ -87,6 +87,8 @@
// scss-docs-start navbar-nav-css-vars
--#{$prefix}nav-link-padding-x: 0;
--#{$prefix}nav-link-padding-y: #{$nav-link-padding-y};
@include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size);
--#{$prefix}nav-link-font-weight: #{$nav-link-font-weight};
--#{$prefix}nav-link-color: var(--#{$prefix}navbar-color);
--#{$prefix}nav-link-hover-color: var(--#{$prefix}navbar-hover-color);
--#{$prefix}nav-link-disabled-color: var(--#{$prefix}navbar-disabled-color);
+1 -1
View File
@@ -87,7 +87,7 @@ hr {
font-style: $headings-font-style;
font-weight: $headings-font-weight;
line-height: $headings-line-height;
color: var(--#{$prefix}heading-color);
color: $headings-color;
}
h1 {
-1
View File
@@ -64,7 +64,6 @@
--#{$prefix}border-radius-pill: #{$border-radius-pill};
// scss-docs-end root-border-var
--#{$prefix}heading-color: #{$headings-color};
--#{$prefix}link-color: #{$link-color};
--#{$prefix}link-hover-color: #{$link-hover-color};
+1 -1
View File
@@ -116,5 +116,5 @@
color: var(--#{$prefix}tooltip-color);
text-align: center;
background-color: var(--#{$prefix}tooltip-bg);
border-radius: var(--#{$prefix}tooltip-border-radius, 0); // stylelint-disable-line property-disallowed-list
@include border-radius(var(--#{$prefix}tooltip-border-radius));
}
+1 -1
View File
@@ -616,7 +616,7 @@ $small-font-size: .875em !default;
$sub-sup-font-size: .75em !default;
$text-muted: rgba(var(--#{$prefix}body-color-rgb), .75) !default;
$text-muted: $gray-600 !default;
$initialism-font-size: $small-font-size !default;
+6 -3
View File
@@ -59,13 +59,12 @@
opacity: 1;
}
// Disabled and read-only inputs
// Disabled inputs
//
// HTML5 says that controls under a fieldset > legend:first-child won't be
// disabled if the fieldset is disabled. Due to implementation difficulty, we
// don't honor that edge case; we style them as disabled anyway.
&:disabled,
&[readonly] {
&:disabled {
color: $input-disabled-color;
background-color: $input-disabled-bg;
border-color: $input-disabled-border-color;
@@ -110,6 +109,10 @@
border: solid transparent;
border-width: $input-border-width 0;
&:focus {
outline: 0;
}
&.form-control-sm,
&.form-control-lg {
padding-right: 0;
+5
View File
@@ -78,6 +78,11 @@
@each $pseudo in $state {
.#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {
@each $property in $properties {
@if $is-local-vars {
@each $local-var, $variable in $is-local-vars {
--#{$prefix}#{$local-var}: #{$variable};
}
}
#{$property}: $value if($enable-important-utilities, !important, null);
}
}
+9 -5
View File
@@ -102,7 +102,9 @@
// Indeterminate checkbox example in docs and StackBlitz
document.querySelectorAll('.bd-example-indeterminate [type="checkbox"]')
.forEach(checkbox => {
checkbox.indeterminate = true
if (checkbox.id.includes('Indeterminate')) {
checkbox.indeterminate = true
}
})
// -------------------------------
@@ -141,10 +143,12 @@
// Offcanvas
// -------------------------------
// 'Offcanvas components' example in docs only
const myOffcanvas = document.querySelector('.bd-example-offcanvas #offcanvas')
const myOffcanvas = document.querySelectorAll('.bd-example-offcanvas .offcanvas')
if (myOffcanvas) {
myOffcanvas.addEventListener('show.bs.offcanvas', event => {
event.preventDefault()
}, false)
myOffcanvas.forEach(offcanvas => {
offcanvas.addEventListener('show.bs.offcanvas', event => {
event.preventDefault()
}, false)
})
}
})()
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -23,7 +23,7 @@
--docsearch-muted-color: #{$text-muted};
--docsearch-hit-shadow: none;
z-index: 1030;
z-index: 2000; // Make sure to be over all components showcased in the documentation
@include media-breakpoint-up(lg) {
padding-top: 4rem;
+1 -1
View File
@@ -27,7 +27,7 @@ Alerts are available for any length of text, as well as an optional close button
Click the button below to show an alert (hidden with inline styles to start), then dismiss (and destroy) it with the built-in close button.
{{< example js_snippet="true" >}}
{{< example stackblitz_add_js="true" >}}
<div id="liveAlertPlaceholder"></div>
<button type="button" class="btn btn-primary" id="liveAlertBtn">Show live alert</button>
{{< /example >}}
+1 -1
View File
@@ -186,10 +186,10 @@ const bsButton = new bootstrap.Button('#myButton')
{{< bs-table "table" >}}
| Method | Description |
| --- | --- |
| `toggle` | Toggles push state. Gives the button the appearance that it has been activated. |
| `dispose` | Destroys an element's button. (Removes stored data on the DOM element) |
| `getInstance` | Static method which allows you to get the button instance associated to a DOM element, you can use it like this: `bootstrap.Button.getInstance(element)`|
| `getOrCreateInstance` | Static method which returns a button instance associated to a DOM element or create a new one in case it wasn't initialized. You can use it like this: `bootstrap.Button.getOrCreateInstance(element)` |
| `toggle` | Toggles push state. Gives the button the appearance that it has been activated. |
{{< /bs-table >}}
For example, to toggle all buttons
+3 -3
View File
@@ -208,10 +208,10 @@ Add `data-bs-interval=""` to a `.carousel-item` to change the amount of time to
### Disable touch swiping
Carousels support swiping left/right on touchscreen devices to move between slides. This can be disabled using the `data-bs-touch` attribute. The example below also does not include the `data-bs-ride` attribute and has `data-bs-interval="false"` so it doesn't autoplay.
Carousels support swiping left/right on touchscreen devices to move between slides. This can be disabled using the `data-bs-touch` attribute. The example below also does not include the `data-bs-ride` attribute so it doesn't autoplay.
{{< example >}}
<div id="carouselExampleControlsNoTouching" class="carousel slide" data-bs-touch="false" data-bs-interval="false">
<div id="carouselExampleControlsNoTouching" class="carousel slide" data-bs-touch="false">
<div class="carousel-inner">
<div class="carousel-item active">
{{< placeholder width="800" height="400" class="bd-placeholder-img-lg d-block w-100" color="#555" background="#777" text="First slide" >}}
@@ -314,7 +314,7 @@ const carousel = new bootstrap.Carousel('#myCarousel')
{{< bs-table >}}
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `interval` | number | `5000` | The amount of time to delay between automatically cycling an item. If `false`, carousel will not automatically cycle. |
| `interval` | number | `5000` | The amount of time to delay between automatically cycling an item. |
| `keyboard` | boolean | `true` | Whether the carousel should react to keyboard events. |
| `pause` | string, boolean | `"hover"` | If set to `"hover"`, pauses the cycling of the carousel on `mouseenter` and resumes the cycling of the carousel on `mouseleave`. If set to `false`, hovering over the carousel won't pause it. On touch-enabled devices, when set to `"hover"`, cycling will pause on `touchend` (once the user finished interacting with the carousel) for two intervals, before automatically resuming. This is in addition to the mouse behavior. |
| `ride` | string, boolean | `false` | If set to `true`, autoplays the carousel after the user manually cycles the first item. If set to `"carousel"`, autoplays the carousel on load. |
+38 -37
View File
@@ -247,53 +247,54 @@ Place Bootstrap's checkboxes and radios within list group items and customize as
{{< example >}}
<ul class="list-group">
<li class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="" aria-label="...">
First checkbox
<input class="form-check-input me-1" type="checkbox" value="" id="firstCheckbox">
<label class="form-check-label" for="firstCheckbox">First checkbox</label>
</li>
<li class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="" aria-label="...">
Second checkbox
<input class="form-check-input me-1" type="checkbox" value="" id="secondCheckbox">
<label class="form-check-label" for="secondCheckbox">Second checkbox</label>
</li>
<li class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="" aria-label="...">
Third checkbox
</li>
<li class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="" aria-label="...">
Fourth checkbox
</li>
<li class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="" aria-label="...">
Fifth checkbox
<input class="form-check-input me-1" type="checkbox" value="" id="thirdCheckbox">
<label class="form-check-label" for="thirdCheckbox">Third checkbox</label>
</li>
</ul>
{{< /example >}}
And if you want `<label>`s as the `.list-group-item` for large hit areas, you can do that, too.
{{< example >}}
<ul class="list-group">
<li class="list-group-item">
<input class="form-check-input me-1" type="radio" name="listGroupRadio" value="" id="firstRadio" checked>
<label class="form-check-label" for="firstRadio">First radio</label>
</li>
<li class="list-group-item">
<input class="form-check-input me-1" type="radio" name="listGroupRadio" value="" id="secondRadio">
<label class="form-check-label" for="secondRadio">Second radio</label>
</li>
<li class="list-group-item">
<input class="form-check-input me-1" type="radio" name="listGroupRadio" value="" id="thirdRadio">
<label class="form-check-label" for="thirdRadio">Third radio</label>
</li>
</ul>
{{< /example >}}
You can use `.stretched-link` on `<label>`s to make the whole list group item clickable.
{{< example >}}
<div class="list-group">
<label class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="">
First checkbox
</label>
<label class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="">
Second checkbox
</label>
<label class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="">
Third checkbox
</label>
<label class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="">
Fourth checkbox
</label>
<label class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="">
Fifth checkbox
</label>
</div>
<ul class="list-group">
<li class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="" id="firstCheckboxStretched">
<label class="form-check-label stretched-link" for="firstCheckboxStretched">First checkbox</label>
</li>
<li class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="" id="secondCheckboxStretched">
<label class="form-check-label stretched-link" for="secondCheckboxStretched">Second checkbox</label>
</li>
<li class="list-group-item">
<input class="form-check-input me-1" type="checkbox" value="" id="thirdCheckboxStretched">
<label class="form-check-label stretched-link" for="thirdCheckboxStretched">Third checkbox</label>
</li>
</ul>
{{< /example >}}
## CSS
+1 -1
View File
@@ -444,7 +444,7 @@ Have a bunch of buttons that all trigger the same modal with slightly different
Below is a live demo followed by example HTML and JavaScript. For more information, [read the modal events docs](#events) for details on `relatedTarget`.
{{< example js_snippet="true" >}}
{{< example stackblitz_add_js="true" >}}
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@mdo">Open modal for @mdo</button>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@fat">Open modal for @fat</button>
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal" data-bs-whatever="@getbootstrap">Open modal for @getbootstrap</button>
+47 -1
View File
@@ -670,7 +670,7 @@ When you do this, we recommend including additional JavaScript to move the focus
### Offcanvas
Transform your expanding and collapsing navbar into an offcanvas drawer with the offcanvas plugin. We extend both the offcanvas default styles and use our `.navbar-expand-*` classes to create a dynamic and flexible navigation sidebar.
Transform your expanding and collapsing navbar into an offcanvas drawer with the [offcanvas component]({{< docsref "/components/offcanvas" >}}). We extend both the offcanvas default styles and use our `.navbar-expand-*` classes to create a dynamic and flexible navigation sidebar.
In the example below, to create an offcanvas navbar that is always collapsed across all breakpoints, omit the `.navbar-expand-*` class entirely.
@@ -732,6 +732,52 @@ To create an offcanvas navbar that expands into a normal navbar at a specific br
</nav>
```
When using offcanvas in a dark navbar, be aware that you may need to have a dark background on the offcanvas content to avoid the text becoming illegible. In the example below, we add `.navbar-dark` and `.bg-dark` to the `.navbar`, `.text-bg-dark` to the `.offcanvas`, `.dropdown-menu-dark` to `.dropdown-menu`, and `.btn-close-white` to `.btn-close` for proper styling with a dark offcanvas.
{{< example >}}
<nav class="navbar navbar-dark bg-dark fixed-top">
<div class="container-fluid">
<a class="navbar-brand" href="#">Offcanvas dark navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="offcanvas" data-bs-target="#offcanvasDarkNavbar" aria-controls="offcanvasDarkNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="offcanvas offcanvas-end text-bg-dark" tabindex="-1" id="offcanvasDarkNavbar" aria-labelledby="offcanvasDarkNavbarLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasDarkNavbarLabel">Dark offcanvas</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav justify-content-end flex-grow-1 pe-3">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu dropdown-menu-dark">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
</ul>
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-success" type="submit">Search</button>
</form>
</div>
</div>
</div>
</nav>
{{< /example >}}
## CSS
### Variables
@@ -79,6 +79,22 @@ You can use a link with the `href` attribute, or a button with the `data-bs-targ
</div>
{{< /example >}}
### Dark offcanvas
Change the appearance of offcanvases with utilities to better match them to different contexts like dark navbars. Here we add `.text-bg-dark` to the `.offcanvas` and `.btn-close-white` to `.btn-close` for proper styling with a dark offcanvas. If you have dropdowns within, consider also adding `.dropdown-menu-dark` to `.dropdown-menu`.
{{< example class="bd-example-offcanvas p-0 bg-light overflow-hidden" >}}
<div class="offcanvas offcanvas-start show text-bg-dark" tabindex="-1" id="offcanvasDark" aria-labelledby="offcanvasDarkLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasDarkLabel">Offcanvas</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvasDark" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<p>Place offcanvas content here.</p>
</div>
</div>
{{< /example >}}
### Body scrolling
Scrolling the `<body>` element is disabled when an offcanvas and its backdrop are visible. Use the `data-bs-scroll` attribute to enable `<body>` scrolling.
+15 -11
View File
@@ -44,17 +44,21 @@ const popoverList = [...popoverTriggerList].map(popoverTriggerEl => new bootstra
### Live demo
We use JavaScript similar to the snippet above to render the following live popover. Titles are set via `title` attribute and body content is set via `data-bs-content`.
We use JavaScript similar to the snippet above to render the following live popover. Titles are set via `data-bs-title` and body content is set via `data-bs-content`.
{{< example js_snippet="true" >}}
<button type="button" class="btn btn-lg btn-danger" data-bs-toggle="popover" title="Popover title" data-bs-content="And here's some amazing content. It's very engaging. Right?">Click to toggle popover</button>
{{< callout warning >}}
{{< partial "callout-warning-data-bs-title-vs-title.md" >}}
{{< /callout >}}
{{< example stackblitz_add_js="true" >}}
<button type="button" class="btn btn-lg btn-danger" data-bs-toggle="popover" data-bs-title="Popover title" data-bs-content="And here's some amazing content. It's very engaging. Right?">Click to toggle popover</button>
{{< /example >}}
### Four directions
Four options are available: top, right, bottom, and left. Directions are mirrored when using Bootstrap in RTL. Set `data-bs-placement` to change the direction.
{{< example js_snippet="true" >}}
{{< example stackblitz_add_js="true" >}}
<button type="button" class="btn btn-secondary" data-bs-container="body" data-bs-toggle="popover" data-bs-placement="top" data-bs-content="Top popover">
Popover on top
</button>
@@ -87,11 +91,11 @@ You can customize the appearance of popovers using [CSS variables](#variables).
{{< scss-docs name="custom-popovers" file="site/assets/scss/_component-examples.scss" >}}
{{< example class="custom-popover-demo" js_snippet="true" >}}
{{< example class="custom-popover-demo" stackblitz_add_js="true" >}}
<button type="button" class="btn btn-secondary"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-custom-class="custom-popover"
title="Custom popover"
data-bs-title="Custom popover"
data-bs-content="This popover is themed via CSS variables.">
Custom popover
</button>
@@ -107,8 +111,8 @@ Use the `focus` trigger to dismiss popovers on the user's next click of a differ
For proper cross-browser and cross-platform behavior, you must use the `<a>` tag, _not_ the `<button>` tag, and you also must include a [`tabindex`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex) attribute.
{{< /callout >}}
{{< example js_snippet="true" >}}
<a tabindex="0" class="btn btn-lg btn-danger" role="button" data-bs-toggle="popover" data-bs-trigger="focus" title="Dismissible popover" data-bs-content="And here's some amazing content. It's very engaging. Right?">Dismissible popover</a>
{{< example stackblitz_add_js="true" >}}
<a tabindex="0" class="btn btn-lg btn-danger" role="button" data-bs-toggle="popover" data-bs-trigger="focus" data-bs-title="Dismissible popover" data-bs-content="And here's some amazing content. It's very engaging. Right?">Dismissible popover</a>
{{< /example >}}
```js
@@ -123,7 +127,7 @@ Elements with the `disabled` attribute aren't interactive, meaning users cannot
For disabled popover triggers, you may also prefer `data-bs-trigger="hover focus"` so that the popover appears as immediate visual feedback to your users as they may not expect to _click_ on a disabled element.
{{< example js_snippet="true" >}}
{{< example stackblitz_add_js="true" >}}
<span class="d-inline-block" tabindex="0" data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-content="Disabled popover">
<button class="btn btn-primary" type="button" disabled>Disabled button</button>
</span>
@@ -258,11 +262,11 @@ The `setContent` method accepts an `object` argument, where each property-key is
{{< bs-table >}}
| Event | Description |
| --- | --- |
| `show.bs.popover` | This event fires immediately when the `show` instance method is called. |
| `shown.bs.popover` | This event is fired when the popover has been made visible to the user (will wait for CSS transitions to complete). |
| `hide.bs.popover` | This event is fired immediately when the `hide` instance method has been called. |
| `hidden.bs.popover` | This event is fired when the popover has finished being hidden from the user (will wait for CSS transitions to complete). |
| `inserted.bs.popover` | This event is fired after the `show.bs.popover` event when the popover template has been added to the DOM. |
| `show.bs.popover` | This event fires immediately when the `show` instance method is called. |
| `shown.bs.popover` | This event is fired when the popover has been made visible to the user (will wait for CSS transitions to complete). |
{{< /bs-table >}}
```js
+86 -80
View File
@@ -162,53 +162,55 @@ Scrollspy also works with nested `.nav`s. If a nested `.nav` is `.active`, its p
</div>
```html
<div class="col-4">
<nav id="navbar-example3" class="h-100 flex-column align-items-stretch pe-4 border-end">
<nav class="nav nav-pills flex-column">
<a class="nav-link" href="#item-1">Item 1</a>
<div class="row">
<div class="col-4">
<nav id="navbar-example3" class="h-100 flex-column align-items-stretch pe-4 border-end">
<nav class="nav nav-pills flex-column">
<a class="nav-link ms-3 my-1" href="#item-1-1">Item 1-1</a>
<a class="nav-link ms-3 my-1" href="#item-1-2">Item 1-2</a>
</nav>
<a class="nav-link" href="#item-2">Item 2</a>
<a class="nav-link" href="#item-3">Item 3</a>
<nav class="nav nav-pills flex-column">
<a class="nav-link ms-3 my-1" href="#item-3-1">Item 3-1</a>
<a class="nav-link ms-3 my-1" href="#item-3-2">Item 3-2</a>
<a class="nav-link" href="#item-1">Item 1</a>
<nav class="nav nav-pills flex-column">
<a class="nav-link ms-3 my-1" href="#item-1-1">Item 1-1</a>
<a class="nav-link ms-3 my-1" href="#item-1-2">Item 1-2</a>
</nav>
<a class="nav-link" href="#item-2">Item 2</a>
<a class="nav-link" href="#item-3">Item 3</a>
<nav class="nav nav-pills flex-column">
<a class="nav-link ms-3 my-1" href="#item-3-1">Item 3-1</a>
<a class="nav-link ms-3 my-1" href="#item-3-2">Item 3-2</a>
</nav>
</nav>
</nav>
</nav>
</div>
</div>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#navbar-example3" data-bs-smooth-scroll="true" class="scrollspy-example-2" tabindex="0">
<div id="item-1">
<h4>Item 1</h4>
<p>...</p>
</div>
<div id="item-1-1">
<h5>Item 1-1</h5>
<p>...</p>
</div>
<div id="item-1-2">
<h5>Item 1-2</h5>
<p>...</p>
</div>
<div id="item-2">
<h4>Item 2</h4>
<p>...</p>
</div>
<div id="item-3">
<h4>Item 3</h4>
<p>...</p>
</div>
<div id="item-3-1">
<h5>Item 3-1</h5>
<p>...</p>
</div>
<div id="item-3-2">
<h5>Item 3-2</h5>
<p>...</p>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#navbar-example3" data-bs-smooth-scroll="true" class="scrollspy-example-2" tabindex="0">
<div id="item-1">
<h4>Item 1</h4>
<p>...</p>
</div>
<div id="item-1-1">
<h5>Item 1-1</h5>
<p>...</p>
</div>
<div id="item-1-2">
<h5>Item 1-2</h5>
<p>...</p>
</div>
<div id="item-2">
<h4>Item 2</h4>
<p>...</p>
</div>
<div id="item-3">
<h4>Item 3</h4>
<p>...</p>
</div>
<div id="item-3-1">
<h5>Item 3-1</h5>
<p>...</p>
</div>
<div id="item-3-2">
<h5>Item 3-2</h5>
<p>...</p>
</div>
</div>
</div>
</div>
@@ -244,24 +246,26 @@ Scrollspy also works with `.list-group`s. Scroll the area next to the list group
</div>
```html
<div class="col-4">
<div id="list-example" class="list-group">
<a class="list-group-item list-group-item-action" href="#list-item-1">Item 1</a>
<a class="list-group-item list-group-item-action" href="#list-item-2">Item 2</a>
<a class="list-group-item list-group-item-action" href="#list-item-3">Item 3</a>
<a class="list-group-item list-group-item-action" href="#list-item-4">Item 4</a>
<div class="row">
<div class="col-4">
<div id="list-example" class="list-group">
<a class="list-group-item list-group-item-action" href="#list-item-1">Item 1</a>
<a class="list-group-item list-group-item-action" href="#list-item-2">Item 2</a>
<a class="list-group-item list-group-item-action" href="#list-item-3">Item 3</a>
<a class="list-group-item list-group-item-action" href="#list-item-4">Item 4</a>
</div>
</div>
</div>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#list-example" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
<h4 id="list-item-1">Item 1</h4>
<p>...</p>
<h4 id="list-item-2">Item 2</h4>
<p>...</p>
<h4 id="list-item-3">Item 3</h4>
<p>...</p>
<h4 id="list-item-4">Item 4</h4>
<p>...</p>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#list-example" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
<h4 id="list-item-1">Item 1</h4>
<p>...</p>
<h4 id="list-item-2">Item 2</h4>
<p>...</p>
<h4 id="list-item-3">Item 3</h4>
<p>...</p>
<h4 id="list-item-4">Item 4</h4>
<p>...</p>
</div>
</div>
</div>
```
@@ -299,27 +303,29 @@ Scrollspy is not limited to nav components and list groups, so it will work on a
</div>
```html
<div class="col-4">
<div id="list-example" class="d-flex flex-column gap-2 simple-list-example-scrollspy text-center">
<a class="p-1 rounded" href="#simple-list-item-1">Item 1</a>
<a class="p-1 rounded" href="#simple-list-item-2">Item 2</a>
<a class="p-1 rounded" href="#simple-list-item-3">Item 3</a>
<a class="p-1 rounded" href="#simple-list-item-4">Item 4</a>
<a class="p-1 rounded" href="#simple-list-item-5">Item 5</a>
<div class="row">
<div class="col-4">
<div id="simple-list-example" class="d-flex flex-column gap-2 simple-list-example-scrollspy text-center">
<a class="p-1 rounded" href="#simple-list-item-1">Item 1</a>
<a class="p-1 rounded" href="#simple-list-item-2">Item 2</a>
<a class="p-1 rounded" href="#simple-list-item-3">Item 3</a>
<a class="p-1 rounded" href="#simple-list-item-4">Item 4</a>
<a class="p-1 rounded" href="#simple-list-item-5">Item 5</a>
</div>
</div>
</div>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#list-example" data-bs-offset="0" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
<h4 id="simple-list-item-1">Item 1</h4>
<p>...</p>
<h4 id="simple-list-item-2">Item 2</h4>
<p>...</p>
<h4 id="simple-list-item-3">Item 3</h4>
<p>...</p>
<h4 id="simple-list-item-4">Item 4</h4>
<p>...</p>
<h4 id="simple-list-item-5">Item 5</h4>
<p>...</p>
<div class="col-8">
<div data-bs-spy="scroll" data-bs-target="#simple-list-example" data-bs-offset="0" data-bs-smooth-scroll="true" class="scrollspy-example" tabindex="0">
<h4 id="simple-list-item-1">Item 1</h4>
<p>...</p>
<h4 id="simple-list-item-2">Item 2</h4>
<p>...</p>
<h4 id="simple-list-item-3">Item 3</h4>
<p>...</p>
<h4 id="simple-list-item-4">Item 4</h4>
<p>...</p>
<h4 id="simple-list-item-5">Item 5</h4>
<p>...</p>
</div>
</div>
</div>
```
+1 -1
View File
@@ -197,7 +197,7 @@ Building on the above example, you can create different toast color schemes with
Place toasts with custom CSS as you need them. The top right is often used for notifications, as is the top middle. If you're only ever going to show one toast at a time, put the positioning styles right on the `.toast`.
{{< example js_snippet="true" >}}
{{< example stackblitz_add_js="true" >}}
<form>
<div class="mb-3">
<label for="selectToastPlacement">Toast placement</label>
+38 -34
View File
@@ -45,11 +45,15 @@ const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstra
Hover over the links below to see tooltips:
{{< example class="tooltip-demo" js_snippet="true" >}}
<p class="muted">Placeholder text to demonstrate some <a href="#" data-bs-toggle="tooltip" title="Default tooltip">inline links</a> with tooltips. This is now just filler, no killer. Content placed here just to mimic the presence of <a href="#" data-bs-toggle="tooltip" title="Another tooltip">real text</a>. And all that just to give you an idea of how tooltips would look when used in real-world situations. So hopefully you've now seen how <a href="#" data-bs-toggle="tooltip" title="Another one here too">these tooltips on links</a> can work in practice, once you use them on <a href="#" data-bs-toggle="tooltip" title="The last tip!">your own</a> site or project.
{{< example class="tooltip-demo" stackblitz_add_js="true" >}}
<p class="muted">Placeholder text to demonstrate some <a href="#" data-bs-toggle="tooltip" data-bs-title="Default tooltip">inline links</a> with tooltips. This is now just filler, no killer. Content placed here just to mimic the presence of <a href="#" data-bs-toggle="tooltip" data-bs-title="Another tooltip">real text</a>. And all that just to give you an idea of how tooltips would look when used in real-world situations. So hopefully you've now seen how <a href="#" data-bs-toggle="tooltip" data-bs-title="Another one here too">these tooltips on links</a> can work in practice, once you use them on <a href="#" data-bs-toggle="tooltip" data-bs-title="The last tip!">your own</a> site or project.
</p>
{{< /example >}}
{{< callout warning >}}
{{< partial "callout-warning-data-bs-title-vs-title.md" >}}
{{< /callout >}}
### Custom tooltips
{{< added-in "5.2.0" >}}
@@ -59,11 +63,11 @@ You can customize the appearance of tooltips using [CSS variables](#variables).
{{< scss-docs name="custom-tooltip" file="site/assets/scss/_component-examples.scss" >}}
{{< example class="tooltip-demo" js_snippet="true" >}}
{{< example class="tooltip-demo" stackblitz_add_js="true" >}}
<button type="button" class="btn btn-secondary"
data-bs-toggle="tooltip" data-bs-placement="top"
data-bs-custom-class="custom-tooltip"
title="This top tooltip is themed via CSS variables.">
data-bs-title="This top tooltip is themed via CSS variables.">
Custom tooltip
</button>
{{< /example >}}
@@ -74,25 +78,25 @@ Hover over the buttons below to see the four tooltips directions: top, right, bo
<div class="bd-example tooltip-demo">
<div class="bd-example-tooltips">
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top">Tooltip on top</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="right" title="Tooltip on right">Tooltip on right</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Tooltip on bottom">Tooltip on bottom</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="left" title="Tooltip on left">Tooltip on left</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-html="true" title="<em>Tooltip</em> <u>with</u> <b>HTML</b>">Tooltip with HTML</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Tooltip on top">Tooltip on top</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Tooltip on right">Tooltip on right</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Tooltip on bottom">Tooltip on bottom</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="left" data-bs-title="Tooltip on left">Tooltip on left</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-html="true" data-bs-title="<em>Tooltip</em> <u>with</u> <b>HTML</b>">Tooltip with HTML</button>
</div>
</div>
```html
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" title="Tooltip on top">
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Tooltip on top">
Tooltip on top
</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="right" title="Tooltip on right">
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="right" data-bs-title="Tooltip on right">
Tooltip on right
</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" title="Tooltip on bottom">
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Tooltip on bottom">
Tooltip on bottom
</button>
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="left" title="Tooltip on left">
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="left" data-bs-title="Tooltip on left">
Tooltip on left
</button>
```
@@ -100,7 +104,7 @@ Hover over the buttons below to see the four tooltips directions: top, right, bo
And with custom HTML added:
```html
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-html="true" title="<em>Tooltip</em> <u>with</u> <b>HTML</b>">
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-html="true" data-bs-title="<em>Tooltip</em> <u>with</u> <b>HTML</b>">
Tooltip with HTML
</button>
```
@@ -108,7 +112,7 @@ And with custom HTML added:
With an SVG:
<div class="bd-example tooltip-demo">
<a href="#" class="d-inline-block" data-bs-toggle="tooltip" title="Default tooltip">
<a href="#" class="d-inline-block" data-bs-toggle="tooltip" data-bs-title="Default tooltip">
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 100 100">
<rect width="100%" height="100%" fill="#563d7c"/>
<circle cx="50" cy="50" r="30" fill="#007bff"/>
@@ -165,7 +169,7 @@ You should only add tooltips to HTML elements that are traditionally keyboard-fo
```html
<!-- HTML to write -->
<a href="#" data-bs-toggle="tooltip" title="Some tooltip text!">Hover over me</a>
<a href="#" data-bs-toggle="tooltip" data-bs-title="Some tooltip text!">Hover over me</a>
<!-- Generated markup by the plugin -->
<div class="tooltip bs-tooltip-top" role="tooltip">
@@ -182,7 +186,7 @@ Elements with the `disabled` attribute aren't interactive, meaning users cannot
<div class="tooltip-demo">
{{< example >}}
<span class="d-inline-block" tabindex="0" data-bs-toggle="tooltip" title="Disabled tooltip">
<span class="d-inline-block" tabindex="0" data-bs-toggle="tooltip" data-bs-title="Disabled tooltip">
<button class="btn btn-primary" type="button" disabled>Disabled button</button>
</span>
{{< /example >}}
@@ -202,23 +206,23 @@ Note that for security reasons the `sanitize`, `sanitizeFn`, and `allowList` opt
{{< bs-table "table" >}}
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `allowList` | object | [Default value]({{< docsref "/getting-started/javascript#sanitizer" >}}) | Object which contains allowed attributes and tags. |
| `animation` | boolean | `true` | Apply a CSS fade transition to the tooltip |
| `boundary` | string, element | `'clippingParents'` | Overflow constraint boundary of the tooltip (applies only to Popper's preventOverflow modifier). By default, it's `'clippingParents'` and can accept an HTMLElement reference (via JavaScript only). For more information refer to Popper's [detectOverflow docs](https://popper.js.org/docs/v2/utils/detect-overflow/#boundary). |
| `container` | string, element, false | `false` | Appends the tooltip to a specific element. Example: `container: 'body'`. This option is particularly useful in that it allows you to position the tooltip in the flow of the document near the triggering element - which will prevent the tooltip from floating away from the triggering element during a window resize. |
| `customClass` | string, function | `''` | Add classes to the tooltip when it is shown. Note that these classes will be added in addition to any classes specified in the template. To add multiple classes, separate them with spaces: `'class-1 class-2'`. You can also pass a function that should return a single string containing additional class names. |
| `delay` | number, object | `0` | Delay showing and hiding the tooltip (ms)—doesn't apply to manual trigger type. If a number is supplied, delay is applied to both hide/show. Object structure is: `delay: { "show": 500, "hide": 100 }`. |
| `fallbackPlacements` | string, array | `['top', 'right', 'bottom', 'left']` | Define fallback placements by providing a list of placements in array (in order of preference). For more information refer to Popper's [behavior docs](https://popper.js.org/docs/v2/modifiers/flip/#fallbackplacements. |
| `html` | boolean | `false` | Allow HTML in the tooltip. If true, HTML tags in the tooltip's `title` will be rendered in the tooltip. If false, `innerText` property will be used to insert content into the DOM. Use text if you're worried about XSS attacks. |
| `offset` | number, string, function | `[0, 0]` | Offset of the tooltip relative to its target. You can pass a string in data attributes with comma separated values like: `data-bs-offset="10,20"`. When a function is used to determine the offset, it is called with an object containing the popper placement, the reference, and popper rects as its first argument. The triggering element DOM node is passed as the second argument. The function must return an array with two numbers: [skidding](https://popper.js.org/docs/v2/modifiers/offset/#skidding-1), [distance](https://popper.js.org/docs/v2/modifiers/offset/#distance-1). For more information refer to Popper's [offset docs](https://popper.js.org/docs/v2/modifiers/offset/#options). |
| `placement` | string, function | `'top'` | How to position the tooltip: auto, top, bottom, left, right. When `auto` is specified, it will dynamically reorient the tooltip. When a function is used to determine the placement, it is called with the tooltip DOM node as its first argument and the triggering element DOM node as its second. The `this` context is set to the tooltip instance. |
| `popperConfig` | null, object, function | `null` | To change Bootstrap's default Popper config, see [Popper's configuration](https://popper.js.org/docs/v2/constructors/#options). When a function is used to create the Popper configuration, it's called with an object that contains the Bootstrap's default Popper configuration. It helps you use and merge the default with your own configuration. The function must return a configuration object for Popper.|
| `sanitize` | boolean | `true` | Enable or disable the sanitization. If activated `'template'`, `'content'` and `'title'` options will be sanitized. |
| `sanitizeFn` | null, function | `null` | Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization. |
| `selector` | string, false | `false` | If a selector is provided, tooltip objects will be delegated to the specified targets. In practice, this is used to also apply tooltips to dynamically added DOM elements (`jQuery.on` support). See [this issue]({{< param repo >}}/issues/4215) and [an informative example](https://codepen.io/Johann-S/pen/djJYPb). |
| `template` | string | `'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'` | Base HTML to use when creating the tooltip. The tooltip's `title` will be injected into the `.tooltip-inner`. `.tooltip-arrow` will become the tooltip's arrow. The outermost wrapper element should have the `.tooltip` class and `role="tooltip"`. |
| `title` | string, element, function | `''` | Default title value if `title` attribute isn't present. If a function is given, it will be called with its `this` reference set to the element that the popover is attached to. |
| `customClass` | string, function | `''` | Add classes to the tooltip when it is shown. Note that these classes will be added in addition to any classes specified in the template. To add multiple classes, separate them with spaces: `'class-1 class-2'`. You can also pass a function that should return a single string containing additional class names. |
| `trigger` | string | `'hover focus'` | How tooltip is triggered: click, hover, focus, manual. You may pass multiple triggers; separate them with a space. `'manual'` indicates that the tooltip will be triggered programmatically via the `.tooltip('show')`, `.tooltip('hide')` and `.tooltip('toggle')` methods; this value cannot be combined with any other trigger. `'hover'` on its own will result in tooltips that cannot be triggered via the keyboard, and should only be used if alternative methods for conveying the same information for keyboard users is present. |
| `offset` | number, string, function | `[0, 0]` | Offset of the tooltip relative to its target. You can pass a string in data attributes with comma separated values like: `data-bs-offset="10,20"`. When a function is used to determine the offset, it is called with an object containing the popper placement, the reference, and popper rects as its first argument. The triggering element DOM node is passed as the second argument. The function must return an array with two numbers: [skidding](https://popper.js.org/docs/v2/modifiers/offset/#skidding-1), [distance](https://popper.js.org/docs/v2/modifiers/offset/#distance-1). For more information refer to Popper's [offset docs](https://popper.js.org/docs/v2/modifiers/offset/#options). |
| `fallbackPlacements` | string, array | `['top', 'right', 'bottom', 'left']` | Define fallback placements by providing a list of placements in array (in order of preference). For more information refer to Popper's [behavior docs](https://popper.js.org/docs/v2/modifiers/flip/#fallbackplacements. |
| `boundary` | string, element | `'clippingParents'` | Overflow constraint boundary of the tooltip (applies only to Popper's preventOverflow modifier). By default, it's `'clippingParents'` and can accept an HTMLElement reference (via JavaScript only). For more information refer to Popper's [detectOverflow docs](https://popper.js.org/docs/v2/utils/detect-overflow/#boundary). |
| `sanitize` | boolean | `true` | Enable or disable the sanitization. If activated `'template'`, `'content'` and `'title'` options will be sanitized. |
| `allowList` | object | [Default value]({{< docsref "/getting-started/javascript#sanitizer" >}}) | Object which contains allowed attributes and tags. |
| `sanitizeFn` | null, function | `null` | Here you can supply your own sanitize function. This can be useful if you prefer to use a dedicated library to perform sanitization. |
| `popperConfig` | null, object, function | `null` | To change Bootstrap's default Popper config, see [Popper's configuration](https://popper.js.org/docs/v2/constructors/#options). When a function is used to create the Popper configuration, it's called with an object that contains the Bootstrap's default Popper configuration. It helps you use and merge the default with your own configuration. The function must return a configuration object for Popper.|
{{< /bs-table >}}
{{< callout info >}}
@@ -248,17 +252,17 @@ const tooltip = new bootstrap.Tooltip(element, {
{{< bs-table "table" >}}
| Method | Description |
| --- | --- |
| `show` | Reveals an element's tooltip. **Returns to the caller before the tooltip has actually been shown** (i.e. before the `shown.bs.tooltip` event occurs). This is considered a "manual" triggering of the tooltip. Tooltips with zero-length titles are never displayed. |
| `hide` | Hides an element's tooltip. **Returns to the caller before the tooltip has actually been hidden** (i.e. before the `hidden.bs.tooltip` event occurs). This is considered a "manual" triggering of the tooltip. |
| `toggle` | Toggles an element's tooltip. **Returns to the caller before the tooltip has actually been shown or hidden** (i.e. before the `shown.bs.tooltip` or `hidden.bs.tooltip` event occurs). This is considered a "manual" triggering of the tooltip. |
| `disable` | Removes the ability for an element's tooltip to be shown. The tooltip will only be able to be shown if it is re-enabled. |
| `dispose` | Hides and destroys an element's tooltip (Removes stored data on the DOM element). Tooltips that use delegation (which are created using [the `selector` option](#options)) cannot be individually destroyed on descendant trigger elements. |
| `enable` | Gives an element's tooltip the ability to be shown. **Tooltips are enabled by default.** |
| `disable` | Removes the ability for an element's tooltip to be shown. The tooltip will only be able to be shown if it is re-enabled. |
| `setContent` | Gives a way to change the tooltip's content after its initialization. |
| `toggleEnabled` | Toggles the ability for an element's tooltip to be shown or hidden. |
| `update` | Updates the position of an element's tooltip. |
| `getInstance` | *Static* method which allows you to get the tooltip instance associated with a DOM element, or create a new one in case it wasn't initialized |
| `getOrCreateInstance` | *Static* method which allows you to get the tooltip instance associated with a DOM element, or create a new one in case it wasn't initialized |
| `hide` | Hides an element's tooltip. **Returns to the caller before the tooltip has actually been hidden** (i.e. before the `hidden.bs.tooltip` event occurs). This is considered a "manual" triggering of the tooltip. |
| `setContent` | Gives a way to change the tooltip's content after its initialization. |
| `show` | Reveals an element's tooltip. **Returns to the caller before the tooltip has actually been shown** (i.e. before the `shown.bs.tooltip` event occurs). This is considered a "manual" triggering of the tooltip. Tooltips with zero-length titles are never displayed. |
| `toggle` | Toggles an element's tooltip. **Returns to the caller before the tooltip has actually been shown or hidden** (i.e. before the `shown.bs.tooltip` or `hidden.bs.tooltip` event occurs). This is considered a "manual" triggering of the tooltip. |
| `toggleEnabled` | Toggles the ability for an element's tooltip to be shown or hidden. |
| `update` | Updates the position of an element's tooltip. |
{{< /bs-table >}}
```js
@@ -278,11 +282,11 @@ The `setContent` method accepts an `object` argument, where each property-key is
{{< bs-table >}}
| Event | Description |
| --- | --- |
| `show.bs.tooltip` | This event fires immediately when the `show` instance method is called. |
| `shown.bs.tooltip` | This event is fired when the popover has been made visible to the user (will wait for CSS transitions to complete). |
| `hide.bs.tooltip` | This event is fired immediately when the `hide` instance method has been called. |
| `hidden.bs.tooltip` | This event is fired when the popover has finished being hidden from the user (will wait for CSS transitions to complete). |
| `inserted.bs.tooltip` | This event is fired after the `show.bs.tooltip` event when the tooltip template has been added to the DOM. |
| `show.bs.tooltip` | This event fires immediately when the `show` instance method is called. |
| `shown.bs.tooltip` | This event is fired when the popover has been made visible to the user (will wait for CSS transitions to complete). |
{{< /bs-table >}}
```js
+1 -1
View File
@@ -77,7 +77,7 @@ Whenever possible, be sure to compress all the code you serve to your visitors.
While minifying and using compression might seem like enough, making your files non-blocking ones is also a big step in making your site well-optimized and fast enough.
If you are using a [Lighthouse](https://developers.google.com/web/tools/lighthouse/) plugin in Google Chrome, you may have stumbled over FCP. [The First Contentful Paint](https://web.dev/fcp/) metric measures the time from when the page starts loading to when any part of the page's content is rendered on the screen.
If you are using a [Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/) plugin in Google Chrome, you may have stumbled over FCP. [The First Contentful Paint](https://web.dev/fcp/) metric measures the time from when the page starts loading to when any part of the page's content is rendered on the screen.
You can improve FCP by deferring non-critical JavaScript or CSS. What does that mean? Simply, JavaScript or stylesheets that don't need to be present on the first paint of your page should be marked with `async` or `defer` attributes.
+4 -3
View File
@@ -160,18 +160,19 @@ $theme-colors: map-merge($theme-colors, $custom-colors);
### Remove from map
To remove colors from `$theme-colors`, or any other map, use `map-remove`. Be aware you must insert it between our requirements and options:
To remove colors from `$theme-colors`, or any other map, use `map-remove`. Be aware you must insert `$theme-colors` between our requirements just after its definition in `variables` and before its usage in `maps`:
```scss
// Required
@import "../node_modules/bootstrap/scss/functions";
@import "../node_modules/bootstrap/scss/variables";
$theme-colors: map-remove($theme-colors, "info", "light", "dark");
@import "../node_modules/bootstrap/scss/maps";
@import "../node_modules/bootstrap/scss/mixins";
@import "../node_modules/bootstrap/scss/root";
$theme-colors: map-remove($theme-colors, "info", "light", "dark");
// Optional
@import "../node_modules/bootstrap/scss/reboot";
@import "../node_modules/bootstrap/scss/type";
@@ -28,7 +28,7 @@ extra_js:
<div class="container-fluid">
<div class="row">
<nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
<div class="position-sticky pt-3">
<div class="position-sticky pt-3 sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">
@@ -32,10 +32,7 @@ body {
}
.sidebar-sticky {
position: relative;
top: 0;
height: calc(100vh - 48px);
padding-top: .5rem;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
}
@@ -28,10 +28,7 @@ body {
}
.sidebar-sticky {
position: relative;
top: 0;
height: calc(100vh - 48px);
padding-top: .5rem;
overflow-x: hidden;
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
}
@@ -27,7 +27,7 @@ extra_js:
<div class="container-fluid">
<div class="row">
<nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-light sidebar collapse">
<div class="position-sticky pt-3">
<div class="position-sticky pt-3 sidebar-sticky">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">
+8 -2
View File
@@ -36,7 +36,7 @@ Our checks use custom Bootstrap icons to indicate checked or indeterminate state
Checkboxes can utilize the `:indeterminate` pseudo class when manually set via JavaScript (there is no available HTML attribute for specifying it).
{{< example class="bd-example-indeterminate" js_snippet="true" >}}
{{< example class="bd-example-indeterminate" stackblitz_add_js="true" >}}
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckIndeterminate">
<label class="form-check-label" for="flexCheckIndeterminate">
@@ -49,7 +49,13 @@ Checkboxes can utilize the `:indeterminate` pseudo class when manually set via J
Add the `disabled` attribute and the associated `<label>`s are automatically styled to match with a lighter color to help indicate the input's state.
{{< example >}}
{{< example class="bd-example-indeterminate" stackblitz_add_js="true" >}}
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckIndeterminateDisabled" disabled>
<label class="form-check-label" for="flexCheckIndeterminateDisabled">
Disabled indeterminate checkbox
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckDisabled" disabled>
<label class="form-check-label" for="flexCheckDisabled">
+3 -3
View File
@@ -31,7 +31,7 @@ Set heights using classes like `.form-control-lg` and `.form-control-sm`.
## Disabled
Add the `disabled` boolean attribute on an input to give it a grayed out appearance and remove pointer events.
Add the `disabled` boolean attribute on an input to give it a grayed out appearance, remove pointer events, and prevent focusing.
{{< example >}}
<input class="form-control" type="text" placeholder="Disabled input" aria-label="Disabled input example" disabled>
@@ -40,7 +40,7 @@ Add the `disabled` boolean attribute on an input to give it a grayed out appeara
## Readonly
Add the `readonly` boolean attribute on an input to prevent modification of the input's value.
Add the `readonly` boolean attribute on an input to prevent modification of the input's value. `readonly` inputs can still be focused and selected, while `disabled` inputs cannot.
{{< example >}}
<input class="form-control" type="text" value="Readonly input here..." aria-label="readonly input example" readonly>
@@ -48,7 +48,7 @@ Add the `readonly` boolean attribute on an input to prevent modification of the
## Readonly plain text
If you want to have `<input readonly>` elements in your form styled as plain text, use the `.form-control-plaintext` class to remove the default form field styling and preserve the correct margin and padding.
If you want to have `<input readonly>` elements in your form styled as plain text, replace `.form-control` with `.form-control-plaintext` to remove the default form field styling and preserve the correct `margin` and `padding`.
{{< example >}}
<div class="mb-3 row">
@@ -19,7 +19,7 @@ While the Bootstrap CSS can be used with any framework, **the Bootstrap JavaScri
A better alternative for those using this type of frameworks is to use a framework-specific package **instead of** the Bootstrap JavaScript. Here are some of the most popular options:
- React: [React Bootstrap](https://react-bootstrap.github.io/)
- Vue: [BootstrapVue](https://bootstrap-vue.org/)
- Vue: [BootstrapVue](https://bootstrap-vue.org/) (currently only supports Vue 2 and Bootstrap 4)
- Angular: [ng-bootstrap](https://ng-bootstrap.github.io/)
## Using Bootstrap as a module
+73 -71
View File
@@ -63,77 +63,79 @@ Bootstrap's grid system can adapt across all six default breakpoints, and any br
As noted above, each of these breakpoints have their own container, unique class prefix, and modifiers. Here's how the grid changes across these breakpoints:
<table class="table mb-4">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">
xs<br>
<span class="fw-normal">&lt;576px</span>
</th>
<th scope="col">
sm<br>
<span class="fw-normal">&ge;576px</span>
</th>
<th scope="col">
md<br>
<span class="fw-normal">&ge;768px</span>
</th>
<th scope="col">
lg<br>
<span class="fw-normal">&ge;992px</span>
</th>
<th scope="col">
xl<br>
<span class="fw-normal">&ge;1200px</span>
</th>
<th scope="col">
xxl<br>
<span class="fw-normal">&ge;1400px</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<th class="text-nowrap" scope="row">Container <code class="fw-normal">max-width</code></th>
<td>None (auto)</td>
<td>540px</td>
<td>720px</td>
<td>960px</td>
<td>1140px</td>
<td>1320px</td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Class prefix</th>
<td><code>.col-</code></td>
<td><code>.col-sm-</code></td>
<td><code>.col-md-</code></td>
<td><code>.col-lg-</code></td>
<td><code>.col-xl-</code></td>
<td><code>.col-xxl-</code></td>
</tr>
<tr>
<th class="text-nowrap" scope="row"># of columns</th>
<td colspan="6">12</td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Gutter width</th>
<td colspan="6">1.5rem (.75rem on left and right)</td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Custom gutters</th>
<td colspan="6"><a href="{{< docsref "/layout/gutters" >}}">Yes</a></td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Nestable</th>
<td colspan="6"><a href="#nesting">Yes</a></td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Column ordering</th>
<td colspan="6"><a href="{{< docsref "/layout/columns#reordering" >}}">Yes</a></td>
</tr>
</tbody>
</table>
<div class="table-responsive">
<table class="table mb-4">
<thead>
<tr>
<th scope="col"></th>
<th scope="col">
xs<br>
<span class="fw-normal">&lt;576px</span>
</th>
<th scope="col">
sm<br>
<span class="fw-normal">&ge;576px</span>
</th>
<th scope="col">
md<br>
<span class="fw-normal">&ge;768px</span>
</th>
<th scope="col">
lg<br>
<span class="fw-normal">&ge;992px</span>
</th>
<th scope="col">
xl<br>
<span class="fw-normal">&ge;1200px</span>
</th>
<th scope="col">
xxl<br>
<span class="fw-normal">&ge;1400px</span>
</th>
</tr>
</thead>
<tbody>
<tr>
<th class="text-nowrap" scope="row">Container <code class="fw-normal">max-width</code></th>
<td>None (auto)</td>
<td>540px</td>
<td>720px</td>
<td>960px</td>
<td>1140px</td>
<td>1320px</td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Class prefix</th>
<td><code>.col-</code></td>
<td><code>.col-sm-</code></td>
<td><code>.col-md-</code></td>
<td><code>.col-lg-</code></td>
<td><code>.col-xl-</code></td>
<td><code>.col-xxl-</code></td>
</tr>
<tr>
<th class="text-nowrap" scope="row"># of columns</th>
<td colspan="6">12</td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Gutter width</th>
<td colspan="6">1.5rem (.75rem on left and right)</td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Custom gutters</th>
<td colspan="6"><a href="{{< docsref "/layout/gutters" >}}">Yes</a></td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Nestable</th>
<td colspan="6"><a href="#nesting">Yes</a></td>
</tr>
<tr>
<th class="text-nowrap" scope="row">Column ordering</th>
<td colspan="6"><a href="{{< docsref "/layout/columns#reordering" >}}">Yes</a></td>
</tr>
</tbody>
</table>
</div>
## Auto-layout columns
+1
View File
@@ -388,6 +388,7 @@ Want more information? [Read the v5.1.0 blog post.](https://blog.getbootstrap.co
### Navbars
- <span class="badge bg-danger">Breaking</span> Navbars now require a container within (to drastically simplify spacing requirements and CSS required).
- <span class="badge bg-danger">Breaking</span> The `.active` class can no longer be applied to `.nav-item`s, it must be applied directly on `.nav-link`s.
### Offcanvas
+1 -1
View File
@@ -32,7 +32,7 @@ Where *value* is one of:
- `flex`
- `inline-flex`
The display values can be altered by changing the `$displays` variable and recompiling the SCSS.
The display values can be altered by changing the `display` values defined in `$utilities` and recompiling the SCSS.
The media queries affect screen widths with the given breakpoint *or larger*. For example, `.d-lg-none` sets `display: none;` on `lg`, `xl`, and `xxl` screens.
-5
View File
@@ -1,8 +1,3 @@
- name: العربية
code: ar
description: Bootstrap 5 باللغة العربية
url: https://bootstrap.mahdi.style/
- name: 中文(繁體)
code: zh-tw
description: Bootstrap 4 繁體中文手冊
@@ -0,0 +1 @@
Feel free to use either `title` or `data-bs-title` in your HTML. When `title` is used, Popper will replace it automatically with `data-bs-title` when the element is rendered.
+1 -1
View File
@@ -11,7 +11,7 @@
{{- end }}
<li class="nav-item dropdown">
<button class="btn btn-link nav-link py-2 px-0 px-lg-2 dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" data-bs-display="static">
<button type="button" class="btn btn-link nav-link py-2 px-0 px-lg-2 dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" data-bs-display="static">
<span class="d-lg-none" aria-hidden="true">Bootstrap</span><span class="visually-hidden">Bootstrap&nbsp;</span> v{{ .Site.Params.docs_version }} <span class="visually-hidden">(switch to other versions)</span>
</button>
<ul class="dropdown-menu dropdown-menu-end">
+1
View File
@@ -18,6 +18,7 @@
<li class="mb-2"><a href="/">Home</a></li>
<li class="mb-2"><a href="/docs/{{ .Site.Params.docs_version }}/">Docs</a></li>
<li class="mb-2"><a href="/docs/{{ .Site.Params.docs_version }}/examples/">Examples</a></li>
<li class="mb-2"><a href="{{ .Site.Params.icons }}">Icons</a></li>
<li class="mb-2"><a href="{{ .Site.Params.themes }}">Themes</a></li>
<li class="mb-2"><a href="{{ .Site.Params.blog }}">Blog</a></li>
<li class="mb-2"><a href="{{ .Site.Params.swag }}">Swag Store</a></li>
+1 -1
View File
@@ -3,7 +3,7 @@
<div class="col-md-8 mx-auto text-center">
<a class="d-flex flex-column flex-lg-row justify-content-center align-items-center mb-4 text-dark lh-sm text-decoration-none" href="https://blog.getbootstrap.com/2022/05/13/bootstrap-5-2-0-beta/">
<strong class="d-sm-inline-block p-2 me-2 mb-2 mb-lg-0 rounded-3 masthead-notice">New in v5.2</strong>
<span class="text-muted">CSS variables, responsive offcanvas, new utilites, and more!</span>
<span class="text-muted">CSS variables, responsive offcanvas, new utilities, and more!</span>
</a>
<img src="/docs/{{ .Site.Params.docs_version }}/assets/brand/bootstrap-logo-shadow.png" width="200" height="165" alt="Bootstrap" class="d-block mx-auto mb-3">
<h1 class="mb-3 fw-semibold">Build fast, responsive sites with&nbsp;Bootstrap</h1>
+5 -4
View File
@@ -27,10 +27,10 @@
btn.addEventListener('click', event => {
const htmlSnippet = event.target.closest('.bd-code-snippet').querySelector('.bd-example').innerHTML
// Get extra classes for this example except '.bd-example'
const classes = Array.from(event.target.closest('.bd-code-snippet').querySelector('.bd-example').classList).filter(x => x !== 'bd-example').join(' ')
// Get extra classes for this example
const classes = Array.from(event.target.closest('.bd-code-snippet').querySelector('.bd-example').classList).join(' ')
const jsSnippet = event.target.closest('.bd-code-snippet').querySelector('.btn-edit').getAttribute('data-js-snippet')
const jsSnippet = event.target.closest('.bd-code-snippet').querySelector('.btn-edit').getAttribute('data-sb-js-snippet')
StackBlitzSDK.openBootstrapSnippet(htmlSnippet, jsSnippet, classes)
})
})
@@ -42,10 +42,11 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{{ .Site.Params.cdn.css }}" rel="stylesheet">
<link href="https://getbootstrap.com/docs/{{ .Site.Params.docs_version }}/assets/css/docs.css" rel="stylesheet">
<title>Bootstrap Example</title>
<${'script'} src="{{ .Site.Params.cdn.js_bundle }}"></${'script'}>
</head>
<body class="p-3 ${classes}">
<body class="p-3 m-0 border-0 ${classes}">
<!-- Example Code -->
${htmlSnippet.replace(/^/gm, ' ')}
+6 -5
View File
@@ -4,17 +4,18 @@
`args` are all optional and can be one of the following:
* id: the `div`'s id - default: ""
* class: any extra class(es) to be added to the `div` - default: ""
* js_snippet: add extra JS snippet to StackBlitz - default: `false`
* show_preview: if the preview should be output in the HTML - default: `true`
* lang: language used to display the code - default: "html"
* show_markup: if the markup should be output in the HTML - default: `true`
* show_preview: if the preview should be output in the HTML - default: `true`
* stackblitz_add_js: if extra JS snippet shoud le added to StackBlitz - default: `false`
*/ -}}
{{- $id := .Get "id" -}}
{{- $class := .Get "class" -}}
{{- $lang := .Get "lang" | default "html" -}}
{{- $show_preview := .Get "show_preview" | default true -}}
{{- $stackblitz_add_js := .Get "stackblitz_add_js" | default false -}}
{{- $show_markup := .Get "show_markup" | default true -}}
{{- $js_snippet := .Get "js_snippet" | default false -}}
{{- $show_preview := .Get "show_preview" | default true -}}
{{- $input := .Inner -}}
<div class="bd-example-snippet bd-code-snippet">
@@ -29,7 +30,7 @@
<div class="d-flex align-items-center highlight-toolbar bg-light ps-3 pe-2 py-1">
<small class="font-monospace text-muted text-uppercase">{{- $lang -}}</small>
<div class="d-flex ms-auto">
<button type="button" class="btn-edit text-nowrap"{{ with $js_snippet }} data-js-snippet="{{ $js_snippet }}"{{ end }} title="Try it on StackBlitz">
<button type="button" class="btn-edit text-nowrap"{{ with $stackblitz_add_js }} data-sb-js-snippet="{{ $stackblitz_add_js }}"{{ end }} title="Try it on StackBlitz">
<svg class="bi" role="img" aria-label="Try it"><use xlink:href="#lightning-charge-fill"/></svg>
</button>
<button type="button" class="btn-clipboard mt-0 me-0" title="Copy to clipboard">