Compare commits

..

1 Commits

Author SHA1 Message Date
GeoSot 04ab8ba426 feat(config.js): provide a setConfig method for all js components 2022-05-31 11:19:25 +03:00
90 changed files with 2454 additions and 2806 deletions
-3
View File
@@ -91,9 +91,7 @@
"scrollspy",
"Segoe",
"semibold",
"socio",
"srcset",
"stackblitz",
"stickied",
"Stylelint",
"subnav",
@@ -110,7 +108,6 @@
"urlize",
"vbtn",
"viewports",
"Vite",
"vstack",
"walkthroughs",
"WCAG",
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
uses: actions/checkout@v3
- name: Run cspell
uses: streetsidesoftware/cspell-action@v2
uses: streetsidesoftware/cspell-action@v1
with:
config: ".cspell.json"
files: "**/*.md"
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: awaiting reply
if: github.event.label.name == 'needs-example'
if: github.event.label.name == 'awaiting-reply'
uses: actions-cool/issues-helper@v3
with:
actions: "create-comment"
+20 -109
View File
@@ -2,131 +2,42 @@
## Our Pledge
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.
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.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
Examples of behavior that contributes to creating a positive environment include:
* 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
- 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
Examples of unacceptable behavior include:
Examples of unacceptable behavior by participants include:
* 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
- 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
## Enforcement Responsibilities
## Our Responsibilities
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 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 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.
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.
## Scope
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.
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.
## Enforcement
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.
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.
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.
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.
## Attribution
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
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/>
+2 -2
View File
@@ -30,7 +30,7 @@ class BaseComponent extends Config {
}
this._element = element
this._config = this._getConfig(config)
this.setConfig(this._getInitialConfig(config))
Data.set(this._element, this.constructor.DATA_KEY, this)
}
@@ -49,7 +49,7 @@ class BaseComponent extends Config {
executeAfterTransition(callback, element, isAnimated)
}
_getConfig(config) {
_getInitialConfig(config) {
config = this._mergeConfigObj(config, this._element)
config = this._configAfterMerge(config)
this._typeCheckConfig(config)
+2 -2
View File
@@ -78,10 +78,10 @@ const Default = {
}
const DefaultType = {
interval: '(number|boolean)', // TODO:v6 remove boolean support
interval: '(number|boolean)',
keyboard: 'boolean',
pause: '(string|boolean)',
ride: '(boolean|string)',
pause: '(string|boolean)',
touch: 'boolean',
wrap: 'boolean'
}
+4 -4
View File
@@ -45,13 +45,13 @@ const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'
const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="collapse"]'
const Default = {
parent: null,
toggle: true
toggle: true,
parent: null
}
const DefaultType = {
parent: '(null|element)',
toggle: 'boolean'
toggle: 'boolean',
parent: '(null|element)'
}
/**
+65 -74
View File
@@ -11,6 +11,7 @@ import { getjQuery } from '../util/index'
* Constants
*/
const namespaceRegex = /[^.]*(?=\..*)\.|.*/
const stripNameRegex = /\..*/
const stripUidRegex = /::\d+$/
const eventRegistry = {} // Events storage
@@ -86,21 +87,21 @@ function getElementEvents(element) {
return eventRegistry[uid]
}
function bootstrapHandler(meta, fn) {
return function (event) {
hydrateObj(event, { delegateTarget: meta.explicitOriginalTarget })
function bootstrapHandler(element, fn) {
return function handler(event) {
event.delegateTarget = element
if (meta.oneOff) {
EventHandler.off(meta.explicitOriginalTarget, event.type, fn)
if (handler.oneOff) {
EventHandler.off(element, event.type, fn)
}
return fn.apply(meta.explicitOriginalTarget, [event])
return fn.apply(element, [event])
}
}
function bootstrapDelegationHandler(meta, fn) {
return function (event) {
const domElements = meta.explicitOriginalTarget.querySelectorAll(meta.delegationSelector)
function bootstrapDelegationHandler(element, selector, fn) {
return function handler(event) {
const domElements = element.querySelectorAll(selector)
for (let { target } = event; target && target !== this; target = target.parentNode) {
for (const domElement of domElements) {
@@ -108,10 +109,10 @@ function bootstrapDelegationHandler(meta, fn) {
continue
}
hydrateObj(event, { delegateTarget: target })
event.delegateTarget = target
if (meta.oneOff) {
EventHandler.off(meta.explicitOriginalTarget, event.type, meta.delegationSelector, fn)
if (handler.oneOff) {
EventHandler.off(element, event.type, selector, fn)
}
return fn.apply(target, [event])
@@ -125,14 +126,26 @@ function findHandler(events, callable, delegationSelector = null) {
.find(event => event.callable === callable && event.delegationSelector === delegationSelector)
}
function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
const isDelegated = typeof handler === 'string'
// todo: tooltip passes `false` instead of selector, so we need to check
const callable = isDelegated ? delegationFunction : (handler || delegationFunction)
let typeEvent = getTypeEvent(originalTypeEvent)
if (!nativeEvents.has(typeEvent)) {
typeEvent = originalTypeEvent
}
return [isDelegated, callable, typeEvent]
}
function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
if (typeof originalTypeEvent !== 'string' || !element) {
return
}
const parameters = new Parameters(handler, delegationFunction)
const meta = new EventMeta(element, originalTypeEvent, parameters, oneOff)
let { callable, isDelegated, delegationSelector } = parameters
let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
// in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
// this prevents the handler from being dispatched the same way as mouseover or mouseout does
if (originalTypeEvent in customEvents) {
@@ -148,8 +161,8 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
}
const events = getElementEvents(element)
const handlers = events[meta.name] || (events[meta.name] = {})
const previousFunction = findHandler(handlers, callable, delegationSelector)
const handlers = events[typeEvent] || (events[typeEvent] = {})
const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)
if (previousFunction) {
previousFunction.oneOff = previousFunction.oneOff && oneOff
@@ -157,14 +170,18 @@ function addHandler(element, originalTypeEvent, handler, delegationFunction, one
return
}
const uid = makeEventUid(callable, meta.namespace)
const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))
const fn = isDelegated ?
bootstrapDelegationHandler(meta, callable) :
bootstrapHandler(meta, callable)
bootstrapDelegationHandler(element, handler, callable) :
bootstrapHandler(element, callable)
handlers[uid] = hydrateObj(hydrateObj(fn, meta), { callable, uidEvent: uid })
fn.delegationSelector = isDelegated ? handler : null
fn.callable = callable
fn.oneOff = oneOff
fn.uidEvent = uid
handlers[uid] = fn
element.addEventListener(meta.name, handlers[uid], isDelegated)
element.addEventListener(typeEvent, fn, isDelegated)
}
function removeHandler(element, events, typeEvent, handler, delegationSelector) {
@@ -189,6 +206,12 @@ function removeNamespacedHandlers(element, events, typeEvent, namespace) {
}
}
function getTypeEvent(event) {
// allow to get the native events from namespaced events ('click.bs.button' --> 'click')
event = event.replace(stripNameRegex, '')
return customEvents[event] || event
}
const EventHandler = {
on(element, event, handler, delegationFunction) {
addHandler(element, event, handler, delegationFunction, false)
@@ -203,35 +226,34 @@ const EventHandler = {
return
}
const parameters = new Parameters(handler, delegationFunction)
const meta = new EventMeta(element, originalTypeEvent, parameters)
const { callable, delegationSelector } = parameters
const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
const inNamespace = typeEvent !== originalTypeEvent
const events = getElementEvents(element)
const storeElementEvent = events[meta.name] || {}
const storeElementEvent = events[typeEvent] || {}
const isNamespace = originalTypeEvent.startsWith('.')
if (callable) {
if (typeof callable !== 'undefined') {
// Simplest case: handler is passed, remove that listener ONLY.
if (!Object.keys(storeElementEvent).length) {
if (!storeElementEvent) {
return
}
removeHandler(element, events, meta.name, callable, delegationSelector)
removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)
return
}
if (meta.isNamespace) {
if (isNamespace) {
for (const elementEvent of Object.keys(events)) {
removeNamespacedHandlers(element, events, elementEvent, meta.namespace)
removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))
}
}
for (const keyHandlers of Object.keys(storeElementEvent)) {
const handlerKey = keyHandlers.replace(stripUidRegex, '')
if (!meta.namespace || originalTypeEvent.includes(handlerKey)) {
if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
const event = storeElementEvent[keyHandlers]
removeHandler(element, events, meta.name, event.callable, event.delegationSelector)
removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
}
}
},
@@ -241,15 +263,16 @@ const EventHandler = {
return null
}
const meta = new EventMeta(element, event)
const $ = getjQuery()
const typeEvent = getTypeEvent(event)
const inNamespace = event !== typeEvent
let jQueryEvent = null
let bubbles = true
let nativeDispatch = true
let defaultPrevented = false
if (meta.namespace && $) {
if (inNamespace && $) {
jQueryEvent = $.Event(event, args)
$(element).trigger(jQueryEvent)
@@ -258,7 +281,7 @@ const EventHandler = {
defaultPrevented = jQueryEvent.isDefaultPrevented()
}
let evt = new Event(meta.name, { bubbles, cancelable: true })
let evt = new Event(event, { bubbles, cancelable: true })
evt = hydrateObj(evt, args)
if (defaultPrevented) {
@@ -277,45 +300,13 @@ const EventHandler = {
}
}
function Parameters(handler, delegationFunction) {
this.isDelegated = typeof handler === 'string'
this.callable = this.isDelegated ?
delegationFunction :
(handler || delegationFunction) // todo: tooltip passes `false` instead of selector, so we need to check
this.delegationSelector = this.isDelegated ? handler : null
}
function EventMeta(element, eventName, parameters = {}, oneOff = false) {
this.givenName = eventName
this.isNamespace = eventName.startsWith('.')
const namespaces = eventName.split('.')
let name = namespaces.shift()
if (!this.isNamespace) {
name = customEvents[name] || name
name = nativeEvents.has(name) ? name : eventName
}
this.name = this.isNamespace ? null : name
this.namespace = namespaces.join('.')
this.explicitOriginalTarget = element
this.delegationSelector = parameters.delegationSelector
this.oneOff = oneOff
}
function hydrateObj(obj, meta) {
for (const [key, value] of Object.entries(meta || {})) {
try {
obj[key] = value
} catch {
Object.defineProperty(obj, key, {
configurable: true,
get() {
return value
}
})
}
Object.defineProperty(obj, key, {
get() {
return value
}
})
}
return obj
+10 -10
View File
@@ -68,21 +68,21 @@ const PLACEMENT_TOPCENTER = 'top'
const PLACEMENT_BOTTOMCENTER = 'bottom'
const Default = {
autoClose: true,
boundary: 'clippingParents',
display: 'dynamic',
offset: [0, 2],
boundary: 'clippingParents',
reference: 'toggle',
display: 'dynamic',
popperConfig: null,
reference: 'toggle'
autoClose: true
}
const DefaultType = {
autoClose: '(boolean|string)',
boundary: '(string|element)',
display: 'string',
offset: '(array|string|function)',
boundary: '(string|element)',
reference: '(string|element|object)',
display: 'string',
popperConfig: '(null|object|function)',
reference: '(string|element|object)'
autoClose: '(boolean|string)'
}
/**
@@ -205,8 +205,8 @@ class Dropdown extends BaseComponent {
EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
}
_getConfig(config) {
config = super._getConfig(config)
_getInitialConfig(config) {
config = super._getInitialConfig(config)
if (typeof config.reference === 'object' && !isElement(config.reference) &&
typeof config.reference.getBoundingClientRect !== 'function'
+6 -6
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_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`
const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`
const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
@@ -46,14 +46,14 @@ const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="modal"]'
const Default = {
backdrop: true,
focus: true,
keyboard: true
keyboard: true,
focus: true
}
const DefaultType = {
backdrop: '(boolean|string)',
focus: 'boolean',
keyboard: 'boolean'
keyboard: 'boolean',
focus: 'boolean'
}
/**
@@ -221,7 +221,7 @@ class Modal extends BaseComponent {
}
})
EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {
EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => {
if (event.target !== event.currentTarget) { // click is inside modal-dialog
return
}
+7 -7
View File
@@ -19,15 +19,15 @@ const SELECTOR_CONTENT = '.popover-body'
const Default = {
...Tooltip.Default,
content: '',
offset: [0, 8],
placement: 'right',
offset: [0, 8],
trigger: 'click',
content: '',
template: '<div class="popover" role="tooltip">' +
'<div class="popover-arrow"></div>' +
'<h3 class="popover-header"></h3>' +
'<div class="popover-body"></div>' +
'</div>',
trigger: 'click'
'<div class="popover-arrow"></div>' +
'<h3 class="popover-header"></h3>' +
'<div class="popover-body"></div>' +
'</div>'
}
const DefaultType = {
+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, behavior: 'smooth' })
root.scrollTo({ top: height })
return
}
+12 -4
View File
@@ -109,9 +109,13 @@ 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 (element.getAttribute('role') !== 'tab') {
if (isAnimated) { // todo: maybe is redundant
element.classList.add(CLASS_NAME_SHOW)
}
if (element.getAttribute('role') !== 'tab') {
return
}
@@ -124,7 +128,7 @@ class Tab extends BaseComponent {
})
}
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
this._queueCallback(complete, element, isAnimated)
}
_deactivate(element, relatedElem) {
@@ -137,9 +141,13 @@ 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 (element.getAttribute('role') !== 'tab') {
if (isAnimated) { // todo maybe is redundant
element.classList.remove(CLASS_NAME_SHOW)
}
if (element.getAttribute('role') !== 'tab') {
return
}
@@ -149,7 +157,7 @@ class Tab extends BaseComponent {
EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })
}
this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
this._queueCallback(complete, element, isAnimated)
}
_keydown(event) {
+43 -43
View File
@@ -54,46 +54,46 @@ const AttachmentMap = {
}
const Default = {
allowList: DefaultAllowlist,
animation: true,
boundary: 'clippingParents',
container: false,
customClass: '',
template: '<div class="tooltip" role="tooltip">' +
'<div class="tooltip-arrow"></div>' +
'<div class="tooltip-inner"></div>' +
'</div>',
trigger: 'hover focus',
title: '',
delay: 0,
fallbackPlacements: ['top', 'right', 'bottom', 'left'],
html: false,
offset: [0, 0],
selector: false,
placement: 'top',
popperConfig: null,
offset: [0, 0],
container: false,
fallbackPlacements: ['top', 'right', 'bottom', 'left'],
boundary: 'clippingParents',
customClass: '',
sanitize: true,
sanitizeFn: null,
selector: false,
template: '<div class="tooltip" role="tooltip">' +
'<div class="tooltip-arrow"></div>' +
'<div class="tooltip-inner"></div>' +
'</div>',
title: '',
trigger: 'hover focus'
allowList: DefaultAllowlist,
popperConfig: null
}
const DefaultType = {
allowList: 'object',
animation: 'boolean',
boundary: '(string|element)',
container: '(string|element|boolean)',
customClass: '(string|function)',
delay: '(number|object)',
fallbackPlacements: 'array',
html: 'boolean',
offset: '(array|string|function)',
placement: '(string|function)',
popperConfig: '(null|object|function)',
sanitize: 'boolean',
sanitizeFn: '(null|function)',
selector: '(string|boolean)',
template: 'string',
title: '(string|element|function)',
trigger: 'string'
trigger: 'string',
delay: '(number|object)',
html: 'boolean',
selector: '(string|boolean)',
placement: '(string|function)',
offset: '(array|string|function)',
container: '(string|element|boolean)',
fallbackPlacements: 'array',
boundary: '(string|element)',
customClass: '(string|function)',
sanitize: 'boolean',
sanitizeFn: '(null|function)',
allowList: 'object',
popperConfig: '(null|object|function)'
}
/**
@@ -115,7 +115,6 @@ class Tooltip extends BaseComponent {
this._activeTrigger = {}
this._popper = null
this._templateFactory = null
this._newContent = null
// Protected
this.tip = null
@@ -206,12 +205,6 @@ 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'))
@@ -226,7 +219,7 @@ class Tooltip extends BaseComponent {
if (this._popper) {
this._popper.update()
} else {
this._popper = this._createPopper(tip)
this._createPopper(tip)
}
tip.classList.add(CLASS_NAME_SHOW)
@@ -312,7 +305,7 @@ class Tooltip extends BaseComponent {
_getTipElement() {
if (!this.tip) {
this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())
this.tip = this._createTipElement(this._getContentForTemplate())
}
return this.tip
@@ -342,11 +335,17 @@ class Tooltip extends BaseComponent {
}
setContent(content) {
this._newContent = content
if (this._isShown()) {
let isShown = false
if (this.tip) {
isShown = this._isShown()
this.tip.remove()
this.tip = null
this._disposePopper()
}
this._disposePopper()
this.tip = this._createTipElement(content)
if (isShown) {
this.show()
}
}
@@ -374,7 +373,7 @@ class Tooltip extends BaseComponent {
}
_getTitle() {
return this._resolvePossibleFunction(this._config.title) || this._config.originalTitle
return this._config.title
}
// Private
@@ -395,7 +394,7 @@ class Tooltip extends BaseComponent {
this._config.placement.call(this, tip, this._element) :
this._config.placement
const attachment = AttachmentMap[placement.toUpperCase()]
return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))
this._popper = Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))
}
_getOffset() {
@@ -563,7 +562,7 @@ class Tooltip extends BaseComponent {
return Object.values(this._activeTrigger).includes(true)
}
_getConfig(config) {
_getInitialConfig(config) {
const dataAttributes = Manipulator.getDataAttributes(this._element)
for (const dataAttribute of Object.keys(dataAttributes)) {
@@ -593,6 +592,7 @@ 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
@@ -20,18 +20,18 @@ const EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`
const Default = {
className: 'modal-backdrop',
clickCallback: null,
isAnimated: false,
isVisible: true, // if false, we use the backdrop helper without adding any element to the dom
rootElement: 'body' // give the choice to place backdrop under different elements
isAnimated: false,
rootElement: 'body', // give the choice to place backdrop under different elements
clickCallback: null
}
const DefaultType = {
className: 'string',
clickCallback: '(function|null)',
isAnimated: 'boolean',
isVisible: 'boolean',
rootElement: '(element|string)'
isAnimated: 'boolean',
rootElement: '(element|string)',
clickCallback: '(function|null)'
}
/**
@@ -41,7 +41,7 @@ const DefaultType = {
class Backdrop extends Config {
constructor(config) {
super()
this._config = this._getConfig(config)
this.setConfig(this._getInitialConfig(config))
this._isAppended = false
this._element = null
}
+11 -2
View File
@@ -13,6 +13,8 @@ import Manipulator from '../dom/manipulator'
*/
class Config {
_config = {}
// Getters
static get Default() {
return {}
@@ -26,10 +28,17 @@ class Config {
throw new Error('You have to implement the static method "NAME", for each component!')
}
_getConfig(config) {
setConfig(config) {
this._typeCheckConfig(config)
this._config = {
...this._config,
...(typeof config === 'object' ? config : {})
}
}
_getInitialConfig(config) {
config = this._mergeConfigObj(config)
config = this._configAfterMerge(config)
this._typeCheckConfig(config)
return config
}
+5 -5
View File
@@ -24,13 +24,13 @@ const TAB_NAV_FORWARD = 'forward'
const TAB_NAV_BACKWARD = 'backward'
const Default = {
autofocus: true,
trapElement: null // The element to trap focus inside of
trapElement: null, // The element to trap focus inside of
autofocus: true
}
const DefaultType = {
autofocus: 'boolean',
trapElement: 'element'
trapElement: 'element',
autofocus: 'boolean'
}
/**
@@ -40,7 +40,7 @@ const DefaultType = {
class FocusTrap extends Config {
constructor(config) {
super()
this._config = this._getConfig(config)
this.setConfig(this._getInitialConfig(config))
this._isActive = false
this._lastTabNavDirection = null
}
+5 -5
View File
@@ -26,15 +26,15 @@ const CLASS_NAME_POINTER_EVENT = 'pointer-event'
const SWIPE_THRESHOLD = 40
const Default = {
endCallback: null,
leftCallback: null,
rightCallback: null
rightCallback: null,
endCallback: null
}
const DefaultType = {
endCallback: '(function|null)',
leftCallback: '(function|null)',
rightCallback: '(function|null)'
rightCallback: '(function|null)',
endCallback: '(function|null)'
}
/**
@@ -50,7 +50,7 @@ class Swipe extends Config {
return
}
this._config = this._getConfig(config)
this.setConfig(this._getInitialConfig(config))
this._deltaX = 0
this._supportPointerEvents = Boolean(window.PointerEvent)
this._initEvents()
+9 -9
View File
@@ -17,28 +17,28 @@ import Config from './config'
const NAME = 'TemplateFactory'
const Default = {
allowList: DefaultAllowlist,
content: {}, // { selector : text , selector2 : text2 , }
extraClass: '',
template: '<div></div>',
content: {}, // { selector : text , selector2 : text2 , }
html: false,
sanitize: true,
sanitizeFn: null,
template: '<div></div>'
allowList: DefaultAllowlist
}
const DefaultType = {
allowList: 'object',
content: 'object',
extraClass: '(string|function)',
template: 'string',
content: 'object',
html: 'boolean',
sanitize: 'boolean',
sanitizeFn: '(null|function)',
template: 'string'
allowList: 'object'
}
const DefaultContentType = {
entry: '(string|element|function|null)',
selector: '(string|element)'
selector: '(string|element)',
entry: '(string|element|function|null)'
}
/**
@@ -48,7 +48,7 @@ const DefaultContentType = {
class TemplateFactory extends Config {
constructor(config) {
super()
this._config = this._getConfig(config)
this.setConfig(this._getInitialConfig(config))
}
// Getters
+7 -7
View File
@@ -406,7 +406,7 @@ describe('Carousel', () => {
Simulator.setType('pointer')
fixtureEl.innerHTML = [
'<div class="carousel">',
'<div class="carousel" data-bs-interval="false">',
' <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">',
'<div class="carousel" data-bs-interval="false">',
' <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">',
'<div class="carousel" data-bs-interval="false">',
' <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">',
'<div class="carousel" data-bs-interval="false">',
' <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">',
'<div class="carousel" data-bs-interval="false">',
' <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"></div>'
fixtureEl.innerHTML = '<div class="carousel" data-bs-interval="false"></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"></div>',
' <div class="carousel" data-bs-interval="false"></div>',
'</div>'
].join('')
-37
View File
@@ -441,41 +441,4 @@ 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
@@ -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="#">Dropdown item</a>',
' <a class="dropdown-item" href="#">Dropdwon item</a>',
' </div>',
'</div>'
].join('')
+6 -13
View File
@@ -641,10 +641,9 @@ describe('Modal', () => {
modalEl.addEventListener('shown.bs.modal', () => {
const spy = spyOn(modal, '_queueCallback').and.callThrough()
const mouseDown = createEvent('mousedown')
modalEl.dispatchEvent(mouseDown)
modalEl.dispatchEvent(mouseDown)
modalEl.click()
modalEl.click()
setTimeout(() => {
expect(spy).toHaveBeenCalledTimes(1)
@@ -710,19 +709,13 @@ 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)
spyOn(modal, 'hide')
modalEl.addEventListener('shown.bs.modal', () => {
const mouseDown = createEvent('mousedown')
modalEl.click()
})
dialogEl.dispatchEvent(mouseDown)
expect(modal.hide).not.toHaveBeenCalled()
modalEl.dispatchEvent(mouseDown)
expect(modal.hide).toHaveBeenCalled()
modalEl.addEventListener('hidden.bs.modal', () => {
expect(document.querySelector('.modal-backdrop')).toBeNull()
resolve()
})
+1 -1
View File
@@ -889,7 +889,7 @@ describe('ScrollSpy', () => {
setTimeout(() => {
if (div.scrollTo) {
expect(clickSpy).toHaveBeenCalledWith({ top: observable.offsetTop - div.offsetTop, behavior: 'smooth' })
expect(clickSpy).toHaveBeenCalledWith({ top: observable.offsetTop - div.offsetTop })
} else {
expect(clickSpy).toHaveBeenCalledWith(observable.offsetTop - div.offsetTop)
}
+2 -2
View File
@@ -904,7 +904,7 @@ describe('Tab', () => {
})
})
it('should add `show` class to tab panes if there is no `.fade` class', () => {
it('should not 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('.tab-content .show')).toHaveSize(1)
expect(fixtureEl.querySelectorAll('.show')).toHaveSize(0)
resolve()
})
+2 -4
View File
@@ -185,7 +185,7 @@ describe('Tooltip', () => {
const tooltipEl = fixtureEl.querySelector('a')
const tooltip = new Tooltip(tooltipEl)
expect(tooltip._getTitle()).toEqual('Another tooltip')
expect(tooltip._config.title).toEqual('Another tooltip')
})
})
@@ -848,7 +848,7 @@ describe('Tooltip', () => {
}, 100)
setTimeout(() => {
expect(insertedFunc).toHaveBeenCalledTimes(2)
expect(insertedFunc).toHaveBeenCalledTimes(1)
resolve()
}, 200)
}, 0)
@@ -1166,7 +1166,6 @@ describe('Tooltip', () => {
tooltip.setContent({ '.tooltip-inner': 'foo' })
expect(tip()).not.toHaveClass('show')
tooltip.show()
expect(tip().querySelector('.tooltip-inner').textContent).toEqual('foo')
})
@@ -1230,7 +1229,6 @@ describe('Tooltip', () => {
})
tooltip.setContent({ '.tooltip': { 0: childContent, jquery: 'jQuery' } })
tooltip.show()
expect(childContent.parentNode).toEqual(tooltip._getTipElement())
})
+43
View File
@@ -37,6 +37,49 @@ describe('Config', () => {
})
})
describe('setConfig', () => {
it('should merge config object', () => {
const instance = new DummyConfigClass()
spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({
testBool: 'boolean',
testString: 'string'
})
instance.setConfig({
testBool: true,
testString: 'foo'
})
expect(instance._config.testBool).toBeTrue()
expect(instance._config.testString).toEqual('foo')
instance.setConfig({
testBool: false,
testString: 'bar'
})
expect(instance._config.testBool).toBeFalse()
expect(instance._config.testString).toEqual('bar')
})
it('should check values before merging them', () => {
const instance = new DummyConfigClass()
spyOnProperty(DummyConfigClass, 'DefaultType', 'get').and.returnValue({
testBool: 'boolean',
testString: 'string'
})
expect(() => {
instance.setConfig({
testBool: 'foo',
testString: true
})
}).toThrowError(TypeError)
})
})
describe('mergeConfigObj', () => {
it('should parse element\'s data attributes and merge it with default config. Element\'s data attributes must excel Defaults', () => {
fixtureEl.innerHTML = '<div id="test" data-bs-test-bool="false" data-bs-test-int="8" data-bs-test-string1="bar"></div>'
+10 -10
View File
@@ -28,8 +28,8 @@
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -50,8 +50,8 @@
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown2" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown2">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -137,10 +137,10 @@
</div>
</div>
<div class="btn-group dropend">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuRight" data-bs-toggle="dropdown" aria-expanded="false">
Dropend
</button>
<div class="dropdown-menu">
<div class="dropdown-menu" aria-labelledby="dropdownMenuRight">
<button class="dropdown-item" type="button">Action</button>
<button class="dropdown-item" type="button">Another action</button>
<button class="dropdown-item" type="button">Something else here</button>
@@ -159,10 +159,10 @@
</div>
</div>
<div class="btn-group dropstart">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropstartMenu" data-bs-toggle="dropdown" aria-expanded="false">
Dropstart
</button>
<div class="dropdown-menu">
<div class="dropdown-menu" aria-labelledby="dropstartMenu">
<button class="dropdown-item" type="button">Action</button>
<button class="dropdown-item" type="button">Another action</button>
<button class="dropdown-item" type="button">Something else here</button>
@@ -187,10 +187,10 @@
</div>
<div class="col-sm-3 mt-4">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" data-bs-display="static" aria-expanded="false">
Dropdown menu without Popper
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
+2 -2
View File
@@ -24,8 +24,8 @@
<a class="nav-link" href="#mdo">@mdo</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown">
<li><a class="dropdown-item" href="#one">One</a></li>
<li><a class="dropdown-item" href="#two">Two</a></li>
<li><a class="dropdown-item" href="#three">Three</a></li>
+1748 -1810
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.18.6",
"@babel/core": "^7.18.6",
"@babel/preset-env": "^7.18.6",
"@babel/cli": "^7.17.10",
"@babel/core": "^7.18.0",
"@babel/preset-env": "^7.18.0",
"@popperjs/core": "^2.11.5",
"@rollup/plugin-babel": "^5.3.1",
"@rollup/plugin-commonjs": "^22.0.1",
"@rollup/plugin-commonjs": "^22.0.0",
"@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.18.0",
"eslint": "^8.16.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.89.0",
"hugo-bin": "^0.87.1",
"ip": "^2.0.0",
"jquery": "^3.6.0",
"karma": "^6.4.0",
"karma": "^6.3.20",
"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.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"karma-jasmine": "^5.0.1",
"karma-jasmine-html-reporter": "^1.7.0",
"karma-rollup-preprocessor": "7.0.7",
"lockfile-lint": "^4.7.5",
"nodemon": "^2.0.18",
"lockfile-lint": "^4.7.4",
"nodemon": "^2.0.16",
"npm-run-all": "^4.1.5",
"postcss": "^8.4.14",
"postcss-cli": "^9.1.0",
"rollup": "^2.75.7",
"rollup": "^2.74.1",
"rollup-plugin-istanbul": "^3.0.0",
"rtlcss": "^3.5.0",
"sass": "^1.53.0",
"sass": "^1.52.1",
"shelljs": "^0.8.5",
"stylelint": "^14.9.1",
"stylelint-config-twbs-bootstrap": "^4.0.0",
"terser": "^5.14.1",
"stylelint": "^14.8.3",
"stylelint-config-twbs-bootstrap": "^3.1.0",
"terser": "^5.13.1",
"vnu-jar": "21.10.12"
},
"files": [
+1 -1
View File
@@ -22,7 +22,7 @@
text-align: center;
white-space: nowrap;
vertical-align: baseline;
@include border-radius(var(--#{$prefix}badge-border-radius));
border-radius: var(--#{$prefix}badge-border-radius, 0); // stylelint-disable-line property-disallowed-list
@include gradient-bg();
// Empty badges collapse automatically
+1 -21
View File
@@ -103,27 +103,7 @@
// scss-docs-start btn-variant-loops
@each $color, $value in $theme-colors {
.btn-#{$color} {
@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);
}
@include button-variant($value, $value);
}
}
+12 -12
View File
@@ -66,18 +66,6 @@
left: 0;
margin-top: var(--#{$prefix}dropdown-spacer);
}
@if $dropdown-padding-y == 0 {
> .dropdown-item:first-child,
> li:first-child .dropdown-item {
@include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius));
}
> .dropdown-item:last-child,
> li:last-child .dropdown-item {
@include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius));
}
}
}
// scss-docs-start responsive-breakpoints
@@ -184,6 +172,18 @@
background-color: transparent; // For `<button>`s
border: 0; // For `<button>`s
// Prevent dropdown overflow if there's no padding
// See https://github.com/twbs/bootstrap/pull/27703
@if $dropdown-padding-y == 0 {
&:first-child {
@include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius));
}
&:last-child {
@include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius));
}
}
&:hover,
&:focus {
color: var(--#{$prefix}dropdown-link-hover-color);
+3 -3
View File
@@ -177,9 +177,9 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003
@return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));
}
// Return WCAG2.1 relative luminance
// See https://www.w3.org/TR/WCAG/#dfn-relative-luminance
// See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio
// Return WCAG2.0 relative luminance
// See https://www.w3.org/WAI/GL/wiki/Relative_luminance
// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
@function luminance($color) {
$rgb: (
"r": red($color),
+1 -1
View File
@@ -116,5 +116,5 @@
color: var(--#{$prefix}tooltip-color);
text-align: center;
background-color: var(--#{$prefix}tooltip-bg);
@include border-radius(var(--#{$prefix}tooltip-border-radius));
border-radius: var(--#{$prefix}tooltip-border-radius, 0); // stylelint-disable-line property-disallowed-list
}
+3 -6
View File
@@ -59,12 +59,13 @@
opacity: 1;
}
// Disabled inputs
// Disabled and read-only 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 {
&:disabled,
&[readonly] {
color: $input-disabled-color;
background-color: $input-disabled-bg;
border-color: $input-disabled-border-color;
@@ -109,10 +110,6 @@
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,11 +78,6 @@
@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);
}
}
+4 -6
View File
@@ -141,12 +141,10 @@
// Offcanvas
// -------------------------------
// 'Offcanvas components' example in docs only
const myOffcanvas = document.querySelectorAll('.bd-example-offcanvas .offcanvas')
const myOffcanvas = document.querySelector('.bd-example-offcanvas #offcanvas')
if (myOffcanvas) {
myOffcanvas.forEach(offcanvas => {
offcanvas.addEventListener('show.bs.offcanvas', event => {
event.preventDefault()
}, false)
})
myOffcanvas.addEventListener('show.bs.offcanvas', event => {
event.preventDefault()
}, false)
}
})()
File diff suppressed because one or more lines are too long
+96
View File
@@ -0,0 +1,96 @@
// Docsearch theming
// stylelint-disable selector-class-pattern
.algolia-autocomplete {
width: 100%;
}
.ds-dropdown-menu {
width: 100%;
padding: $dropdown-padding-y 0;
margin: $dropdown-spacer 0 0;
@include font-size(.875rem);
background-color: $dropdown-bg;
background-clip: padding-box;
border: $dropdown-border-width solid $dropdown-border-color;
@include border-radius($dropdown-border-radius);
box-shadow: $dropdown-box-shadow;
@include media-breakpoint-up(md) {
width: 500px;
margin-top: .5rem;
margin-left: -110px;
}
}
.algolia-docsearch-suggestion--category-header {
padding: .125rem 1rem;
font-weight: 600;
color: $bd-violet;
:not(.algolia-docsearch-suggestion__main) > & {
display: none;
}
.ds-suggestion:not(:first-child) & {
padding-top: .75rem;
margin-top: .75rem;
border-top: 1px solid rgba(0, 0, 0, .1);
}
}
.algolia-docsearch-suggestion--content {
padding: .25rem 1rem;
.ds-cursor & {
background-color: rgba($bd-purple-light, .2);
}
}
.algolia-docsearch-suggestion {
display: block;
text-decoration: none;
}
.algolia-docsearch-suggestion--subcategory-column {
display: none;
}
.algolia-docsearch-suggestion--subcategory-inline {
display: inline;
color: $gray-700;
&::after {
padding: 0 .25rem;
content: "/";
}
}
.algolia-docsearch-suggestion--title {
display: inline;
font-weight: 500;
color: $gray-800;
}
.algolia-docsearch-suggestion--text {
color: $gray-800;
@include font-size(.75rem);
}
.algolia-docsearch-suggestion--highlight {
color: $purple;
background-color: rgba($purple, .1);
}
.algolia-docsearch-footer {
padding: .5rem 1rem 0;
margin-top: .625rem;
@include font-size(.75rem);
color: $gray-600;
border-top: 1px solid rgba(0, 0, 0, .1);
}
.algolia-docsearch-footer--logo {
color: inherit;
}
+1 -1
View File
@@ -23,7 +23,7 @@
--docsearch-muted-color: #{$text-muted};
--docsearch-hit-shadow: none;
z-index: 2000; // Make sure to be over all components showcased in the documentation
z-index: 1030;
@include media-breakpoint-up(lg) {
padding-top: 4rem;
+1
View File
@@ -57,3 +57,4 @@ $enable-cssgrid: true; // stylelint-disable-line scss/dollar-variable-default
// Load docs dependencies
@import "syntax";
@import "anchor";
@import "algolia";
+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 stackblitz_add_js="true" >}}
{{< example js_snippet="true" >}}
<div id="liveAlertPlaceholder"></div>
<button type="button" class="btn btn-primary" id="liveAlertBtn">Show live alert</button>
{{< /example >}}
@@ -94,7 +94,7 @@ $breadcrumb-divider: none;
Since breadcrumbs provide a navigation, it's a good idea to add a meaningful label such as `aria-label="breadcrumb"` to describe the type of navigation provided in the `<nav>` element, as well as applying an `aria-current="page"` to the last item of the set to indicate that it represents the current page.
For more information, see the [ARIA Authoring Practices Guide breadcrumb pattern](https://www.w3.org/WAI/ARIA/apg/patterns/breadcrumb/).
For more information, see the [WAI-ARIA Authoring Practices for the breadcrumb pattern](https://www.w3.org/TR/wai-aria-practices/#breadcrumb).
## CSS
@@ -173,10 +173,10 @@ Place a `.btn-group` within another `.btn-group` when you want dropdown menus mi
<button type="button" class="btn btn-primary">2</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<button id="btnGroupDrop1" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="btnGroupDrop1">
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
</ul>
@@ -204,10 +204,10 @@ Make a set of buttons appear vertically stacked rather than horizontally. **Spli
<button type="button" class="btn btn-primary">Button</button>
<button type="button" class="btn btn-primary">Button</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<button id="btnGroupVerticalDrop1" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="btnGroupVerticalDrop1">
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
</ul>
@@ -215,28 +215,28 @@ Make a set of buttons appear vertically stacked rather than horizontally. **Spli
<button type="button" class="btn btn-primary">Button</button>
<button type="button" class="btn btn-primary">Button</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<button id="btnGroupVerticalDrop2" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="btnGroupVerticalDrop2">
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
</ul>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<button id="btnGroupVerticalDrop3" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="btnGroupVerticalDrop3">
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
</ul>
</div>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<button id="btnGroupVerticalDrop4" type="button" class="btn btn-primary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="btnGroupVerticalDrop4">
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
<li><a class="dropdown-item" href="#">Dropdown link</a></li>
</ul>
+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 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 and has `data-bs-interval="false"` so it doesn't autoplay.
{{< example >}}
<div id="carouselExampleControlsNoTouching" class="carousel slide" data-bs-touch="false">
<div id="carouselExampleControlsNoTouching" class="carousel slide" data-bs-touch="false" data-bs-interval="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. |
| `interval` | number | `5000` | The amount of time to delay between automatically cycling an item. If `false`, carousel will not automatically cycle. |
| `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. |
+1 -1
View File
@@ -98,7 +98,7 @@ Be sure to add `aria-expanded` to the control element. This attribute explicitly
If your control element is targeting a single collapsible element i.e. the `data-bs-target` attribute is pointing to an `id` selector you should add the `aria-controls` attribute to the control element, containing the `id` of the collapsible element. Modern screen readers and similar assistive technologies make use of this attribute to provide users with additional shortcuts to navigate directly to the collapsible element itself.
Note that Bootstrap's current implementation does not cover the various *optional* keyboard interactions described in the [ARIA Authoring Practices Guide accordion pattern](https://www.w3.org/WAI/ARIA/apg/patterns/accordion/) - you will need to include these yourself with custom JavaScript.
Note that Bootstrap's current implementation does not cover the various *optional* keyboard interactions described in the [WAI-ARIA Authoring Practices 1.1 accordion pattern](https://www.w3.org/TR/wai-aria-practices-1.1/#accordion) - you will need to include these yourself with custom JavaScript.
## Sass
+31 -31
View File
@@ -14,7 +14,7 @@ Dropdowns are built on a third party library, [Popper](https://popper.js.org/),
## Accessibility
The [<abbr title="Web Accessibility Initiative">WAI</abbr> <abbr title="Accessible Rich Internet Applications">ARIA</abbr>](https://www.w3.org/TR/wai-aria/) standard defines an actual [`role="menu"` widget](https://www.w3.org/TR/wai-aria/#menu), but this is specific to application-like menus which trigger actions or functions. <abbr title="Accessible Rich Internet Applications">ARIA</abbr> menus can only contain menu items, checkbox menu items, radio button menu items, radio button groups, and sub-menus.
The [<abbr title="Web Accessibility Initiative">WAI</abbr> <abbr title="Accessible Rich Internet Applications">ARIA</abbr>](https://www.w3.org/TR/wai-aria/) standard defines an actual [`role="menu"` widget](https://www.w3.org/WAI/PF/aria/roles#menu), but this is specific to application-like menus which trigger actions or functions. <abbr title="Accessible Rich Internet Applications">ARIA</abbr> menus can only contain menu items, checkbox menu items, radio button menu items, radio button groups, and sub-menus.
Bootstrap's dropdowns, on the other hand, are designed to be generic and applicable to a variety of situations and markup structures. For instance, it is possible to create dropdowns that contain additional inputs and form controls, such as search fields or login forms. For this reason, Bootstrap does not expect (nor automatically add) any of the `role` and `aria-` attributes required for true <abbr title="Accessible Rich Internet Applications">ARIA</abbr> menus. Authors will have to include these more specific attributes themselves.
@@ -30,10 +30,10 @@ Any single `.btn` can be turned into a dropdown toggle with some markup changes.
{{< example >}}
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton1" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown button
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton1">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -45,11 +45,11 @@ And with `<a>` elements:
{{< example >}}
<div class="dropdown">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<a class="btn btn-secondary dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown link
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -353,10 +353,10 @@ Opt into darker dropdowns to match a dark navbar or custom style by adding `.dro
{{< example >}}
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton2" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown button
</button>
<ul class="dropdown-menu dropdown-menu-dark">
<ul class="dropdown-menu dropdown-menu-dark" aria-labelledby="dropdownMenuButton2">
<li><a class="dropdown-item active" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -378,10 +378,10 @@ And putting it to use in a navbar:
<div class="collapse navbar-collapse" id="navbarNavDarkDropdown">
<ul class="navbar-nav">
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<a class="nav-link dropdown-toggle" href="#" id="navbarDarkDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu dropdown-menu-dark">
<ul class="dropdown-menu dropdown-menu-dark" aria-labelledby="navbarDarkDropdownMenuLink">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -406,10 +406,10 @@ Make the dropdown menu centered below the toggle with `.dropdown-center` on the
{{< example >}}
<div class="dropdown-center">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownCenterBtn" data-bs-toggle="dropdown" aria-expanded="false">
Centered dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownCenterBtn">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Action two</a></li>
<li><a class="dropdown-item" href="#">Action three</a></li>
@@ -482,10 +482,10 @@ Make the dropup menu centered above the toggle with `.dropup-center` on the pare
{{< example >}}
<div class="dropup-center dropup">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropupCenterBtn" data-bs-toggle="dropdown" aria-expanded="false">
Centered dropup
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropupCenterBtn">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Action two</a></li>
<li><a class="dropdown-item" href="#">Action three</a></li>
@@ -617,10 +617,10 @@ You can use `<a>` or `<button>` elements as dropdown items.
{{< example >}}
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenu2" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenu2">
<li><button class="dropdown-item" type="button">Action</button></li>
<li><button class="dropdown-item" type="button">Another action</button></li>
<li><button class="dropdown-item" type="button">Something else here</button></li>
@@ -728,10 +728,10 @@ Taking most of the options shown above, here's a small kitchen sink demo of vari
{{< example >}}
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
@@ -913,10 +913,10 @@ Use `data-bs-offset` or `data-bs-reference` to change the location of the dropdo
{{< example >}}
<div class="d-flex">
<div class="dropdown me-1">
<button type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" data-bs-offset="10,20">
<button type="button" class="btn btn-secondary dropdown-toggle" id="dropdownMenuOffset" data-bs-toggle="dropdown" aria-expanded="false" data-bs-offset="10,20">
Offset
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuOffset">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -924,10 +924,10 @@ Use `data-bs-offset` or `data-bs-reference` to change the location of the dropdo
</div>
<div class="btn-group">
<button type="button" class="btn btn-secondary">Reference</button>
<button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false" data-bs-reference="parent">
<button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" id="dropdownMenuReference" data-bs-toggle="dropdown" aria-expanded="false" data-bs-reference="parent">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuReference">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -944,10 +944,10 @@ By default, the dropdown menu is closed when clicking inside or outside the drop
{{< example >}}
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-auto-close="true" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="defaultDropdown" data-bs-toggle="dropdown" data-bs-auto-close="true" aria-expanded="false">
Default dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="defaultDropdown">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
@@ -955,10 +955,10 @@ By default, the dropdown menu is closed when clicking inside or outside the drop
</div>
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-auto-close="inside" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuClickableOutside" data-bs-toggle="dropdown" data-bs-auto-close="inside" aria-expanded="false">
Clickable outside
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuClickableOutside">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
@@ -966,10 +966,10 @@ By default, the dropdown menu is closed when clicking inside or outside the drop
</div>
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuClickableInside" data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
Clickable inside
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuClickableInside">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
@@ -977,10 +977,10 @@ By default, the dropdown menu is closed when clicking inside or outside the drop
</div>
<div class="btn-group">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" data-bs-auto-close="false" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuClickable" data-bs-toggle="dropdown" data-bs-auto-close="false" aria-expanded="false">
Manual close
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuClickable">
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
<li><a class="dropdown-item" href="#">Menu item</a></li>
@@ -1036,10 +1036,10 @@ Add `data-bs-toggle="dropdown"` to a link or button to toggle a dropdown.
```html
<div class="dropdown">
<button type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button id="dLabel" type="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown trigger
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dLabel">
...
</ul>
</div>
+2 -2
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 stackblitz_add_js="true" >}}
{{< example js_snippet="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>
@@ -807,7 +807,7 @@ Activate a modal without writing JavaScript. Set `data-bs-toggle="modal"` on a c
{{% js-dismiss "modal" %}}
{{< callout warning >}}
While both ways to dismiss a modal are supported, keep in mind that dismissing from outside a modal does not match the [ARIA Authoring Practices Guide dialog (modal) pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/). Do this at your own risk.
While both ways to dismiss a modal are supported, keep in mind that dismissing from outside a modal does not match [the WAI-ARIA modal dialog design pattern](https://www.w3.org/TR/wai-aria-practices-1.1/#dialog_modal). Do this at your own risk.
{{< /callout >}}
### Via JavaScript
+9 -55
View File
@@ -52,10 +52,10 @@ Here's an example of all the sub-components included in a responsive light-theme
<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">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<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>
@@ -207,10 +207,10 @@ You can also use dropdowns in your navbar. Dropdown menus require a wrapping ele
<a class="nav-link" href="#">Pricing</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown link
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -523,10 +523,10 @@ Here's an example navbar using `.navbar-nav-scroll` with `style="--bs-scroll-hei
<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">
<a class="nav-link dropdown-toggle" href="#" id="navbarScrollingDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Link
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="navbarScrollingDropdown">
<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>
@@ -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 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.
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.
In the example below, to create an offcanvas navbar that is always collapsed across all breakpoints, omit the `.navbar-expand-*` class entirely.
@@ -695,10 +695,10 @@ In the example below, to create an offcanvas navbar that is always collapsed acr
<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">
<a class="nav-link dropdown-toggle" href="#" id="offcanvasNavbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="offcanvasNavbarDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li>
@@ -732,52 +732,6 @@ 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
@@ -246,7 +246,7 @@ If you need responsive nav variations, consider using a series of [flexbox utili
If you're using navs to provide a navigation bar, be sure to add a `role="navigation"` to the most logical parent container of the `<ul>`, or wrap a `<nav>` element around the whole navigation. Do not add the role to the `<ul>` itself, as this would prevent it from being announced as an actual list by assistive technologies.
Note that navigation bars, even if visually styled as tabs with the `.nav-tabs` class, should **not** be given `role="tablist"`, `role="tab"` or `role="tabpanel"` attributes. These are only appropriate for dynamic tabbed interfaces, as described in the [ARIA Authoring Practices Guide tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel/). See [JavaScript behavior](#javascript-behavior) for dynamic tabbed interfaces in this section for an example. The `aria-current` attribute is not necessary on dynamic tabbed interfaces since our JavaScript handles the selected state by adding `aria-selected="true"` on the active tab.
Note that navigation bars, even if visually styled as tabs with the `.nav-tabs` class, should **not** be given `role="tablist"`, `role="tab"` or `role="tabpanel"` attributes. These are only appropriate for dynamic tabbed interfaces, as described in the [<abbr title="Web Accessibility Initiative">WAI</abbr> <abbr title="Accessible Rich Internet Applications">ARIA</abbr> Authoring Practices](https://www.w3.org/TR/wai-aria-practices/#tabpanel). See [JavaScript behavior](#javascript-behavior) for dynamic tabbed interfaces in this section for an example. The `aria-current` attribute is not necessary on dynamic tabbed interfaces since our JavaScript handles the selected state by adding `aria-selected="true"` on the active tab.
## Using dropdowns
@@ -538,9 +538,9 @@ And with vertical pills. Ideally, for vertical tabs, you should also add `aria-o
### Accessibility
Dynamic tabbed interfaces, as described in the [ARIA Authoring Practices Guide tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabpanel/), require `role="tablist"`, `role="tab"`, `role="tabpanel"`, and additional `aria-` attributes in order to convey their structure, functionality, and current state to users of assistive technologies (such as screen readers). As a best practice, we recommend using `<button>` elements for the tabs, as these are controls that trigger a dynamic change, rather than links that navigate to a new page or location.
Dynamic tabbed interfaces, as described in the [<abbr title="Web Accessibility Initiative">WAI</abbr> <abbr title="Accessible Rich Internet Applications">ARIA</abbr> Authoring Practices 1.2](https://www.w3.org/TR/wai-aria-practices-1.2/#tabpanel), require `role="tablist"`, `role="tab"`, `role="tabpanel"`, and additional `aria-` attributes in order to convey their structure, functionality, and current state to users of assistive technologies (such as screen readers). As a best practice, we recommend using `<button>` elements for the tabs, as these are controls that trigger a dynamic change, rather than links that navigate to a new page or location.
In line with the ARIA Authoring Practices pattern, only the currently active tab receives keyboard focus. When the JavaScript plugin is initialized, it will set `tabindex="-1"` on all inactive tab controls. Once the currently active tab has focus, the cursor keys activate the previous/next tab, with the plugin changing the [roving `tabindex`](https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/) accordingly. However, note that the JavaScript plugin does not distinguish between horizontal and vertical tab lists when it comes to cursor key interactions: regardless of the tab list's orientation, both the up *and* left cursor go to the previous tab, and down *and* right cursor go to the next tab.
In line with the ARIA Authoring Practices pattern, only the currently active tab receives keyboard focus. When the JavaScript plugin is initialized, it will set `tabindex="-1"` on all inactive tab controls. Once the currently active tab has focus, the cursor keys activate the previous/next tab, with the plugin changing the [roving `tabindex`](https://www.w3.org/TR/wai-aria-practices-1.2/#kbd_roving_tabindex) accordingly. However, note that the JavaScript plugin does not distinguish between horizontal and vertical tab lists when it comes to cursor key interactions: regardless of the tab list's orientation, both the up *and* left cursor go to the previous tab, and down *and* right cursor go to the next tab.
{{< callout warning >}}
In general, to facilitate keyboard navigation, it's recommended to make the tab panels themselves focusable as well, unless the first element containing meaningful content inside the tab panel is already focusable. The JavaScript plugin does not try to handle this aspect—where appropriate, you'll need to explicitly make your tab panels focusable by adding `tabindex="0"` in your markup.
+3 -19
View File
@@ -66,10 +66,10 @@ You can use a link with the `href` attribute, or a button with the `data-bs-targ
Some text as placeholder. In real life you can have the elements you have chosen. Like, text, images, lists, etc.
</div>
<div class="dropdown mt-3">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown">
Dropdown button
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -79,22 +79,6 @@ 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.
@@ -279,7 +263,7 @@ Add `data-bs-toggle="offcanvas"` and a `data-bs-target` or `href` to the element
{{% js-dismiss "offcanvas" %}}
{{< callout warning >}}
While both ways to dismiss an offcanvas are supported, keep in mind that dismissing from outside an offcanvas does not match the [ARIA Authoring Practices Guide dialog (modal) pattern](https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/). Do this at your own risk.
While both ways to dismiss an offcanvas are supported, keep in mind that dismissing from outside an offcanvas does not match [the WAI-ARIA modal dialog design pattern](https://www.w3.org/TR/wai-aria-practices-1.1/#dialog_modal). Do this at your own risk.
{{< /callout >}}
### Via JavaScript
+9 -13
View File
@@ -44,21 +44,17 @@ 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 `data-bs-title` 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 `title` attribute and body content is set via `data-bs-content`.
{{< 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 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>
{{< /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 stackblitz_add_js="true" >}}
{{< example js_snippet="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>
@@ -91,11 +87,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" stackblitz_add_js="true" >}}
{{< example class="custom-popover-demo" js_snippet="true" >}}
<button type="button" class="btn btn-secondary"
data-bs-toggle="popover" data-bs-placement="right"
data-bs-custom-class="custom-popover"
data-bs-title="Custom popover"
title="Custom popover"
data-bs-content="This popover is themed via CSS variables.">
Custom popover
</button>
@@ -111,8 +107,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 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_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 >}}
```js
@@ -127,7 +123,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 stackblitz_add_js="true" >}}
{{< example js_snippet="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>
+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 stackblitz_add_js="true" >}}
{{< example js_snippet="true" >}}
<form>
<div class="mb-3">
<label for="selectToastPlacement">Toast placement</label>
+17 -21
View File
@@ -45,15 +45,11 @@ const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstra
Hover over the links below to see tooltips:
{{< 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.
{{< 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.
</p>
{{< /example >}}
{{< callout warning >}}
{{< partial "callout-warning-data-bs-title-vs-title.md" >}}
{{< /callout >}}
### Custom tooltips
{{< added-in "5.2.0" >}}
@@ -63,11 +59,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" stackblitz_add_js="true" >}}
{{< example class="tooltip-demo" js_snippet="true" >}}
<button type="button" class="btn btn-secondary"
data-bs-toggle="tooltip" data-bs-placement="top"
data-bs-custom-class="custom-tooltip"
data-bs-title="This top tooltip is themed via CSS variables.">
title="This top tooltip is themed via CSS variables.">
Custom tooltip
</button>
{{< /example >}}
@@ -78,25 +74,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" 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>
<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>
</div>
</div>
```html
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="Tooltip on top">
<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" data-bs-title="Tooltip on right">
<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" data-bs-title="Tooltip on bottom">
<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" data-bs-title="Tooltip on left">
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip" data-bs-placement="left" title="Tooltip on left">
Tooltip on left
</button>
```
@@ -104,7 +100,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" data-bs-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" title="<em>Tooltip</em> <u>with</u> <b>HTML</b>">
Tooltip with HTML
</button>
```
@@ -112,7 +108,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" data-bs-title="Default tooltip">
<a href="#" class="d-inline-block" data-bs-toggle="tooltip" 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"/>
@@ -169,7 +165,7 @@ You should only add tooltips to HTML elements that are traditionally keyboard-fo
```html
<!-- HTML to write -->
<a href="#" data-bs-toggle="tooltip" data-bs-title="Some tooltip text!">Hover over me</a>
<a href="#" data-bs-toggle="tooltip" title="Some tooltip text!">Hover over me</a>
<!-- Generated markup by the plugin -->
<div class="tooltip bs-tooltip-top" role="tooltip">
@@ -186,7 +182,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" data-bs-title="Disabled tooltip">
<span class="d-inline-block" tabindex="0" data-bs-toggle="tooltip" title="Disabled tooltip">
<button class="btn btn-primary" type="button" disabled>Disabled button</button>
</span>
{{< /example >}}
+2 -2
View File
@@ -106,8 +106,8 @@ The `<hr>` element has been simplified. Similar to browser defaults, `<hr>`s are
<hr>
</div>
<hr class="border border-danger border-2 opacity-50">
<hr class="border border-primary border-3 opacity-75">
<hr class="text-danger border-2 opacity-50">
<hr class="border-primary border-3 opacity-75">
{{< /example >}}
## Lists
+2 -2
View File
@@ -19,7 +19,7 @@ If you're not using a component, comment it out or delete it entirely. For examp
Bootstrap's JavaScript includes every component in our primary dist files (`bootstrap.js` and `bootstrap.min.js`), and even our primary dependency (Popper) with our bundle files (`bootstrap.bundle.js` and `bootstrap.bundle.min.js`). While you're customizing via Sass, be sure to remove related JavaScript.
For instance, assuming you're using your own JavaScript bundler like Webpack, Parcel, or Vite, you'd only import the JavaScript you plan on using. In the example below, we show how to just include our modal JavaScript:
For instance, assuming you're using your own JavaScript bundler like Webpack or Rollup, you'd only import the JavaScript you plan on using. In the example below, we show how to just include our modal JavaScript:
<!-- eslint-skip -->
```js
@@ -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://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.
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.
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.
+2 -2
View File
@@ -215,9 +215,9 @@ In practice, you'd call the function and pass in the color and weight parameters
### Color contrast
In order to meet the [Web Content Accessibility Guidelines (WCAG)](https://www.w3.org/TR/WCAG/) contrast requirements, authors **must** provide a minimum [text color contrast of 4.5:1](https://www.w3.org/TR/WCAG/#contrast-minimum) and a minimum [non-text color contrast of 3:1](https://www.w3.org/TR/WCAG/#non-text-contrast), with very few exceptions.
In order to meet [WCAG 2.0 accessibility standards for color contrast](https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html), authors **must** provide [a contrast ratio of at least 4.5:1](https://www.w3.org/WAI/WCAG20/quickref/20160105/Overview.php#visual-audio-contrast-contrast), with very few exceptions.
To help with this, we included the `color-contrast` function in Bootstrap. It uses the [WCAG contrast ratio algorithm](https://www.w3.org/TR/WCAG/#dfn-contrast-ratio) for calculating contrast thresholds based on [relative luminance](https://www.w3.org/TR/WCAG/#dfn-relative-luminance) in an `sRGB` color space to automatically return a light (`#fff`), dark (`#212529`) or black (`#000`) contrast color based on the specified base color. This function is especially useful for mixins or loops where you're generating multiple classes.
An additional function we include in Bootstrap is the color contrast function, `color-contrast`. It utilizes the [WCAG 2.0 algorithm](https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests) for calculating contrast thresholds based on [relative luminance](https://www.w3.org/WAI/GL/wiki/Relative_luminance) in a `sRGB` color space to automatically return a light (`#fff`), dark (`#212529`) or black (`#000`) contrast color based on the specified base color. This function is especially useful for mixins or loops where you're generating multiple classes.
For example, to generate color swatches from our `$theme-colors` map:
@@ -913,10 +913,10 @@ direction: rtl
{{< example show_markup="false" >}}
<div class="btn-group w-100 align-items-center justify-content-between flex-wrap">
<div class="dropdown">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="dropdownMenuButtonSM" data-bs-toggle="dropdown" aria-expanded="false">
زر القائمة المنسدلة
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButtonSM">
<li><h6 class="dropdown-header">عنوان القائمة المنسدلة</h6></li>
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
@@ -926,10 +926,10 @@ direction: rtl
</ul>
</div>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
زر القائمة المنسدلة
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li><h6 class="dropdown-header">عنوان القائمة المنسدلة</h6></li>
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
@@ -939,10 +939,10 @@ direction: rtl
</ul>
</div>
<div class="dropdown">
<button class="btn btn-secondary btn-lg dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary btn-lg dropdown-toggle" type="button" id="dropdownMenuButtonLG" data-bs-toggle="dropdown" aria-expanded="false">
زر القائمة المنسدلة
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButtonLG">
<li><h6 class="dropdown-header">عنوان القائمة المنسدلة</h6></li>
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
@@ -1026,10 +1026,10 @@ direction: rtl
{{< example show_markup="false" >}}
<div class="btn-group w-100 align-items-center justify-content-between flex-wrap">
<div class="dropend">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropendMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
زر القائمة المنسدلة لليسار
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropendMenuButton">
<li><h6 class="dropdown-header">عنوان القائمة المنسدلة</h6></li>
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
@@ -1039,10 +1039,10 @@ direction: rtl
</ul>
</div>
<div class="dropup">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropupMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
زر القائمة المنسدلة للأعلى
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropupMenuButton">
<li><h6 class="dropdown-header">عنوان القائمة المنسدلة</h6></li>
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
@@ -1052,10 +1052,10 @@ direction: rtl
</ul>
</div>
<div class="dropstart">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropstartMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
زر القائمة المنسدلة لليمين
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropstartMenuButton">
<li><h6 class="dropdown-header">عنوان القائمة المنسدلة</h6></li>
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
@@ -1070,10 +1070,10 @@ direction: rtl
{{< example show_markup="false" >}}
<div class="btn-group">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownRightMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
قائمة منسدلة بمحاذاة نهاية الزر
</button>
<ul class="dropdown-menu dropdown-menu-end">
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownRightMenuButton">
<li><h6 class="dropdown-header">عنوان القائمة المنسدلة</h6></li>
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
@@ -1230,10 +1230,10 @@ direction: rtl
<a class="nav-link" href="#">رابط</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
قائمة منسدلة
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
<li><hr class="dropdown-divider"></li>
@@ -1269,10 +1269,10 @@ direction: rtl
<a class="nav-link" href="#">رابط</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown2" role="button" data-bs-toggle="dropdown" aria-expanded="false">
قائمة منسدلة
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="navbarDropdown2">
<li><a class="dropdown-item" href="#">عمل</a></li>
<li><a class="dropdown-item" href="#">عمل آخر</a></li>
<li><hr class="dropdown-divider"></li>
@@ -912,10 +912,10 @@ body_class: "bg-light"
{{< example show_markup="false" >}}
<div class="btn-group w-100 align-items-center justify-content-between flex-wrap">
<div class="dropdown">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary btn-sm dropdown-toggle" type="button" id="dropdownMenuButtonSM" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown button
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButtonSM">
<li><h6 class="dropdown-header">Dropdown header</h6></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
@@ -925,10 +925,10 @@ body_class: "bg-light"
</ul>
</div>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown button
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<li><h6 class="dropdown-header">Dropdown header</h6></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
@@ -938,10 +938,10 @@ body_class: "bg-light"
</ul>
</div>
<div class="dropdown">
<button class="btn btn-secondary btn-lg dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary btn-lg dropdown-toggle" type="button" id="dropdownMenuButtonLG" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown button
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdownMenuButtonLG">
<li><h6 class="dropdown-header">Dropdown header</h6></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
@@ -1025,10 +1025,10 @@ body_class: "bg-light"
{{< example show_markup="false" >}}
<div class="btn-group w-100 align-items-center justify-content-between flex-wrap">
<div class="dropend">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropendMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
Dropend button
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropendMenuButton">
<li><h6 class="dropdown-header">Dropdown header</h6></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
@@ -1038,10 +1038,10 @@ body_class: "bg-light"
</ul>
</div>
<div class="dropup">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropupMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
Dropup button
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropupMenuButton">
<li><h6 class="dropdown-header">Dropdown header</h6></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
@@ -1051,10 +1051,10 @@ body_class: "bg-light"
</ul>
</div>
<div class="dropstart">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropstartMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
Dropstart button
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropstartMenuButton">
<li><h6 class="dropdown-header">Dropdown header</h6></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
@@ -1069,10 +1069,10 @@ body_class: "bg-light"
{{< example show_markup="false" >}}
<div class="btn-group">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownRightMenuButton" data-bs-toggle="dropdown" aria-expanded="false">
End-aligned menu
</button>
<ul class="dropdown-menu dropdown-menu-end">
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownRightMenuButton">
<li><h6 class="dropdown-header">Dropdown header</h6></li>
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
@@ -1229,10 +1229,10 @@ body_class: "bg-light"
<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">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<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>
@@ -1268,10 +1268,10 @@ body_class: "bg-light"
<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">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown2" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="navbarDropdown2">
<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>
@@ -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 sidebar-sticky">
<div class="position-sticky pt-3">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">
@@ -32,7 +32,10 @@ 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,7 +28,10 @@ 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 sidebar-sticky">
<div class="position-sticky pt-3">
<ul class="nav flex-column">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">
@@ -137,10 +137,10 @@ body_class: ""
</form>
<div class="dropdown text-end">
<a href="#" class="d-block link-dark text-decoration-none dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<a href="#" class="d-block link-dark text-decoration-none dropdown-toggle" id="dropdownUser1" data-bs-toggle="dropdown" aria-expanded="false">
<img src="https://github.com/mdo.png" alt="mdo" width="32" height="32" class="rounded-circle">
</a>
<ul class="dropdown-menu text-small">
<ul class="dropdown-menu text-small" aria-labelledby="dropdownUser1">
<li><a class="dropdown-item" href="#">New project...</a></li>
<li><a class="dropdown-item" href="#">Settings</a></li>
<li><a class="dropdown-item" href="#">Profile</a></li>
@@ -157,10 +157,10 @@ body_class: ""
<header class="py-3 mb-3 border-bottom">
<div class="container-fluid d-grid gap-3 align-items-center" style="grid-template-columns: 1fr 2fr;">
<div class="dropdown">
<a href="#" class="d-flex align-items-center col-lg-4 mb-2 mb-lg-0 link-dark text-decoration-none dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<a href="#" class="d-flex align-items-center col-lg-4 mb-2 mb-lg-0 link-dark text-decoration-none dropdown-toggle" id="dropdownNavLink" data-bs-toggle="dropdown" aria-expanded="false">
<svg class="bi me-2" width="40" height="32"><use xlink:href="#bootstrap"/></svg>
</a>
<ul class="dropdown-menu text-small shadow">
<ul class="dropdown-menu text-small shadow" aria-labelledby="dropdownNavLink">
<li><a class="dropdown-item active" href="#" aria-current="page">Overview</a></li>
<li><a class="dropdown-item" href="#">Inventory</a></li>
<li><a class="dropdown-item" href="#">Customers</a></li>
@@ -177,10 +177,10 @@ body_class: ""
</form>
<div class="flex-shrink-0 dropdown">
<a href="#" class="d-block link-dark text-decoration-none dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<a href="#" class="d-block link-dark text-decoration-none dropdown-toggle" id="dropdownUser2" data-bs-toggle="dropdown" aria-expanded="false">
<img src="https://github.com/mdo.png" alt="mdo" width="32" height="32" class="rounded-circle">
</a>
<ul class="dropdown-menu text-small shadow">
<ul class="dropdown-menu text-small shadow" aria-labelledby="dropdownUser2">
<li><a class="dropdown-item" href="#">New project...</a></li>
<li><a class="dropdown-item" href="#">Settings</a></li>
<li><a class="dropdown-item" href="#">Profile</a></li>
@@ -28,8 +28,8 @@ title: Bottom navbar example
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropup">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropup</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown10" data-bs-toggle="dropdown" aria-expanded="false">Dropup</a>
<ul class="dropdown-menu" aria-labelledby="dropdown10">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -26,10 +26,10 @@ extra_css:
<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">
<a class="nav-link dropdown-toggle" href="#" id="offcanvasNavbarDarkDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="offcanvasNavbarDarkDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li>
@@ -68,10 +68,10 @@ extra_css:
<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">
<a class="nav-link dropdown-toggle" href="#" id="offcanvasNavbarLightDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="offcanvasNavbarLightDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li>
@@ -110,10 +110,10 @@ extra_css:
<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">
<a class="nav-link dropdown-toggle" href="#" id="offcanvasNavbarLgDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="offcanvasNavbarLgDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li>
@@ -25,8 +25,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown01">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -82,8 +82,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown03" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown03">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -116,8 +116,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown04" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown04">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -150,8 +150,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown05" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown05">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -184,8 +184,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown06" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown06">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -218,8 +218,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdownXxl" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdownXxl">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -252,8 +252,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown07" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown07">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -286,8 +286,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown07XL" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown07XL">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -323,8 +323,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown08" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown08">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -355,8 +355,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown09" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown09">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -388,8 +388,8 @@ extra_css:
<a class="nav-link disabled">Disabled</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown10" data-bs-toggle="dropdown" aria-expanded="false">Dropdown</a>
<ul class="dropdown-menu" aria-labelledby="dropdown10">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -31,8 +31,8 @@ aliases: "/docs/5.2/examples/offcanvas/"
<a class="nav-link" href="#">Switch account</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" aria-expanded="false">Settings</a>
<ul class="dropdown-menu">
<a class="nav-link dropdown-toggle" href="#" id="dropdown01" data-bs-toggle="dropdown" aria-expanded="false">Settings</a>
<ul class="dropdown-menu" aria-labelledby="dropdown01">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
@@ -110,11 +110,11 @@ body_class: ""
</ul>
<hr>
<div class="dropdown">
<a href="#" class="d-flex align-items-center text-white text-decoration-none dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<a href="#" class="d-flex align-items-center text-white text-decoration-none dropdown-toggle" id="dropdownUser1" data-bs-toggle="dropdown" aria-expanded="false">
<img src="https://github.com/mdo.png" alt="" width="32" height="32" class="rounded-circle me-2">
<strong>mdo</strong>
</a>
<ul class="dropdown-menu dropdown-menu-dark text-small shadow">
<ul class="dropdown-menu dropdown-menu-dark text-small shadow" aria-labelledby="dropdownUser1">
<li><a class="dropdown-item" href="#">New project...</a></li>
<li><a class="dropdown-item" href="#">Settings</a></li>
<li><a class="dropdown-item" href="#">Profile</a></li>
@@ -166,11 +166,11 @@ body_class: ""
</ul>
<hr>
<div class="dropdown">
<a href="#" class="d-flex align-items-center link-dark text-decoration-none dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<a href="#" class="d-flex align-items-center link-dark text-decoration-none dropdown-toggle" id="dropdownUser2" data-bs-toggle="dropdown" aria-expanded="false">
<img src="https://github.com/mdo.png" alt="" width="32" height="32" class="rounded-circle me-2">
<strong>mdo</strong>
</a>
<ul class="dropdown-menu text-small shadow">
<ul class="dropdown-menu text-small shadow" aria-labelledby="dropdownUser2">
<li><a class="dropdown-item" href="#">New project...</a></li>
<li><a class="dropdown-item" href="#">Settings</a></li>
<li><a class="dropdown-item" href="#">Profile</a></li>
@@ -215,10 +215,10 @@ body_class: ""
</li>
</ul>
<div class="dropdown border-top">
<a href="#" class="d-flex align-items-center justify-content-center p-3 link-dark text-decoration-none dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<a href="#" class="d-flex align-items-center justify-content-center p-3 link-dark text-decoration-none dropdown-toggle" id="dropdownUser3" data-bs-toggle="dropdown" aria-expanded="false">
<img src="https://github.com/mdo.png" alt="mdo" width="24" height="24" class="rounded-circle">
</a>
<ul class="dropdown-menu text-small shadow">
<ul class="dropdown-menu text-small shadow" aria-labelledby="dropdownUser3">
<li><a class="dropdown-item" href="#">New project...</a></li>
<li><a class="dropdown-item" href="#">Settings</a></li>
<li><a class="dropdown-item" href="#">Profile</a></li>
@@ -40,7 +40,6 @@ extra_css:
<li class="d-flex align-items-start mb-1"><a href="{{< docsref "/getting-started/introduction" >}}">Bootstrap quick start guide</a></li>
<li class="d-flex align-items-start mb-1"><a href="{{< docsref "/getting-started/webpack" >}}">Bootstrap Webpack guide</a></li>
<li class="d-flex align-items-start mb-1"><a href="{{< docsref "/getting-started/parcel" >}}">Bootstrap Parcel guide</a></li>
<li class="d-flex align-items-start mb-1"><a href="{{< docsref "/getting-started/vite" >}}">Bootstrap Vite guide</a></li>
<li class="d-flex align-items-start mb-1"><a href="{{< docsref "/getting-started/contribute" >}}">Contributing to Bootstrap</a></li>
</ul>
</div>
+1 -1
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" stackblitz_add_js="true" >}}
{{< example class="bd-example-indeterminate" js_snippet="true" >}}
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="flexCheckIndeterminate">
<label class="form-check-label" for="flexCheckIndeterminate">
+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, remove pointer events, and prevent focusing.
Add the `disabled` boolean attribute on an input to give it a grayed out appearance and remove pointer events.
{{< 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. `readonly` inputs can still be focused and selected, while `disabled` inputs cannot.
Add the `readonly` boolean attribute on an input to prevent modification of the input's value.
{{< 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, replace `.form-control` with `.form-control-plaintext` 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, use the `.form-control-plaintext` class to remove the default form field styling and preserve the correct margin and padding.
{{< example >}}
<div class="mb-3 row">
@@ -10,7 +10,7 @@ toc: true
Plugins can be included individually (using Bootstrap's individual `js/dist/*.js`), or all at once using `bootstrap.js` or the minified `bootstrap.min.js` (don't include both).
If you use a bundler (Webpack, Parcel, Vite...), you can use `/js/dist/*.js` files which are UMD ready.
If you use a bundler (Webpack, Rollup...), you can use `/js/dist/*.js` files which are UMD ready.
## Usage with JavaScript frameworks
@@ -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/) (currently only supports Vue 2 and Bootstrap 4)
- Vue: [BootstrapVue](https://bootstrap-vue.org/)
- Angular: [ng-bootstrap](https://ng-bootstrap.github.io/)
## Using Bootstrap as a module
@@ -1,197 +0,0 @@
---
layout: docs
title: "Bootstrap & Vite"
description: The official guide for how to include and bundle Bootstrap's CSS and JavaScript in your project using Vite.
group: getting-started
toc: true
---
<img class="mb-4 img-fluid rounded-3" srcset="/docs/{{< param docs_version >}}/assets/img/guides/bootstrap-vite.png, /docs/{{< param docs_version >}}/assets/img/guides/bootstrap-vite@2x.png 2x" src="/docs/{{< param docs_version >}}/assets/img/guides/bootstrap-vite.png" width="2000" height="1000" alt="">
{{< callout >}}
**Want to skip to the end?** Download the source code and working demo for this guide from the [twbs/examples repository](https://github.com/twbs/examples/tree/main/vite). You can also [open the example in StackBlitz](https://stackblitz.com/github/twbs/examples/tree/main/vite?file=index.html) for live editing.
{{< /callout >}}
## Setup
We're building a Vite project with Bootstrap from scratch, so there are some prerequisites and up front steps before we can really get started. This guide requires you to have Node.js installed and some familiarity with the terminal.
1. **Create a project folder and setup npm.** We'll create the `my-project` folder and initialize npm with the `-y` argument to avoid it asking us all the interactive questions.
```sh
mkdir my-project && cd my-project
npm init -y
```
2. **Install Vite.** Unlike our Webpack guide, theres only a single build tool dependency here. We use `--save-dev` to signal that this dependency is only for development use and not for production.
```sh
npm i --save-dev vite
```
3. **Install Bootstrap.** Now we can install Bootstrap. We'll also install Popper since our dropdowns, popovers, and tooltips depend on it for their positioning. If you don't plan on using those components, you can omit Popper here.
```sh
npm i --save bootstrap @popperjs/core
```
4. **Install additional dependency.** In addition to Vite and Bootstrap, we need another dependency (Sass) to properly import and bundle Bootstrap's CSS.
```sh
npm i --save-dev sass
```
Now that we have all the necessary dependencies installed and setup, we can get to work creating the project files and importing Bootstrap.
## Project structure
We've already created the `my-project` folder and initialized npm. Now we'll also create our `src` folder, stylesheet, and JavaScript file to round out the project structure. Run the following from `my-project`, or manually create the folder and file structure shown below.
```sh
mkdir {src,src/js,src/scss}
touch src/index.html src/js/main.js src/scss/styles.scss vite.config.js
```
When you're done, your complete project should look like this:
```text
my-project/
├── src/
│ ├── js/
│ │ └── main.js
│ └── scss/
│ | └── styles.scss
| └── index.html
├── package-lock.json
├── package.json
└── vite.config.js
```
At this point, everything is in the right place, but Vite won't work because we haven't filled in our `vite.config.js` yet.
## Configure Vite
With dependencies installed and our project folder ready for us to start coding, we can now configure Vite and run our project locally.
1. **Open `vite.config.js` in your editor.** Since it's blank, we'll need to add some boilerplate config to it so we can start our server. This part of the config tells Vite were to look for our project's JavaScript and how the development server should behave (pulling from the `src` folder with hot reload).
<!-- eslint-skip -->
```js
const path = require('path')
export default {
root: path.resolve(__dirname, 'src'),
server: {
port: 8080,
hot: true
}
}
```
2. **Next we fill in `src/index.html`.** This is the HTML page Vite will load in the browser to utilize the bundled CSS and JS we'll add to it in later steps.
```html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Bootstrap w/ Vite</title>
</head>
<body>
<div class="container py-4 px-3 mx-auto">
<h1>Hello, Bootstrap and Vite!</h1>
<button class="btn btn-primary">Primary button</button>
</div>
<script type="module" src="./js/main.js"></script>
</body>
</html>
```
We're including a little bit of Bootstrap styling here with the `div class="container"` and `<button>` so that we see when Bootstrap's CSS is loaded by Vite.
3. **Now we need an npm script to run Vite.** Open `package.json` and add the `start` script shown below (you should already have the test script). We'll use this script to start our local Vite dev server.
```json
{
// ...
"scripts": {
"start": "vite",
"test": "echo \"Error: no test specified\" && exit 1"
},
// ...
}
```
4. **And finally, we can start Vite.** From the `my-project` folder in your terminal, run that newly added npm script:
```sh
npm start
```
<img class="img-fluid" src="/docs/{{< param docs_version >}}/assets/img/guides/vite-dev-server.png" alt="Vite dev server running">
In the next and final section to this guide, well import all of Bootstraps CSS and JavaScript.
## Import Bootstrap
1. **Set up Bootstrap's Sass import in `vite.config.js`.** Your configuration file is now complete and should match the snippet below. The only new part here is the `resolve` section—we use this to add an alias to our source files inside `node_modules` to keep imports as simple as possible.
<!-- eslint-skip -->
```js
const path = require('path')
export default {
root: path.resolve(__dirname, 'src'),
resolve: {
alias: {
'~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap'),
}
},
server: {
port: 8080,
hot: true
}
}
```
2. **Now, let's import Bootstrap's CSS.** Add the following to `src/scss/styles.scss` to import all of Bootstrap's source Sass.
```scss
// Import all of Bootstrap's CSS
@import "~bootstrap/scss/bootstrap";
```
*You can also import our stylesheets individually if you want. [Read our Sass import docs]({{< docsref "/customize/sass#importing" >}}) for details.*
3. **Next we load the CSS and import Bootstrap's JavaScript.** Add the following to `src/js/main.js` to load the CSS and import all of Bootstrap's JS. Popper will be imported automatically through Bootstrap.
<!-- eslint-skip -->
```js
// Import our custom CSS
import '../scss/styles.scss'
// Import all of Bootstrap's JS
import * as bootstrap from 'bootstrap'
```
You can also import JavaScript plugins individually as needed to keep bundle sizes down:
<!-- eslint-skip -->
```js
import Alert from 'bootstrap/js/dist/alert';
// or, specify which plugins you need:
import { Tooltip, Toast, Popover } from 'bootstrap';
```
*[Read our JavaScript docs]({{< docsref "/getting-started/javascript/" >}}) for more information on how to use Bootstrap's plugins.*
4. **And you're done! 🎉** With Bootstrap's source Sass and JS fully loaded, your local development server should now look like this.
<img class="img-fluid" src="/docs/{{< param docs_version >}}/assets/img/guides/vite-dev-server-bootstrap.png" alt="Vite dev server running with Bootstrap">
Now you can start adding any Bootstrap components you want to use. Be sure to [checkout the complete Vite example project](https://github.com/twbs/examples/tree/main/vite) for how to include additional custom Sass and optimize your build by importing only the parts of Bootstrap's CSS and JS that you need.
{{< markdown >}}
{{< partial "guide-footer.md" >}}
{{< /markdown >}}
@@ -93,7 +93,7 @@ With dependencies installed and our project folder ready for us to start coding,
}
```
2. **Next we fill in our `dist/index.html`.** This is the HTML page Webpack will load in the browser to utilize the bundled CSS and JS we'll add to it in later steps. Before we can do that, we have to give it something to render and include the `output` JS from the previous step.
2. **Next we create our `dist/index.html`.** This is the HTML page Webpack will load in the browser to utilize the bundled CSS and JS we'll add to it in later steps. Before we can do that, we have to give it something to render and include the `output` JS from the previous step.
```html
<!doctype html>
@@ -142,7 +142,7 @@ In the next and final section to this guide, we'll setup the Webpack loaders and
Importing Bootstrap into Webpack requires the loaders we installed in the first section. We've installed them with npm, but now Webpack needs to be configured to use them.
1. **Set up the loaders in `webpack.config.js`.** Your configuration file is now complete and should match the snippet below. The only new part here is the `module` section.
1. **Setup the loaders in `webpack.config.js`.** Your configuration file is now complete and should match the snippet below. The only new part here is the `module` section.
```js
const path = require('path')
+71 -73
View File
@@ -63,79 +63,77 @@ 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:
<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>
<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>
## Auto-layout columns
-1
View File
@@ -388,7 +388,6 @@ 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
View File
@@ -12,7 +12,6 @@
- title: JavaScript
- title: Webpack
- title: Parcel
- title: Vite
- title: Accessibility
- title: RFS
- title: RTL
@@ -1 +0,0 @@
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.
+3 -3
View File
@@ -11,10 +11,10 @@
{{- 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">
<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 class="btn btn-link nav-link py-2 px-0 px-lg-2 dropdown-toggle" id="bd-versions" data-bs-toggle="dropdown" aria-expanded="false" data-bs-display="static">
<span class="d-lg-none">Bootstrap</span> v{{ .Site.Params.docs_version }}
</button>
<ul class="dropdown-menu dropdown-menu-end">
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="bd-versions">
<li><h6 class="dropdown-header">v5 releases</h6></li>
<li>
<a class="dropdown-item current" aria-current="true" href="{{ if .IsHome }}/{{ else }}/docs/{{ .Site.Params.docs_version }}/{{ $versions_link }}{{ end }}">
-1
View File
@@ -30,7 +30,6 @@
<li class="mb-2"><a href="/docs/{{ .Site.Params.docs_version }}/examples/starter-template/">Starter template</a></li>
<li class="mb-2"><a href="/docs/{{ .Site.Params.docs_version }}/getting-started/webpack/">Webpack</a></li>
<li class="mb-2"><a href="/docs/{{ .Site.Params.docs_version }}/getting-started/parcel/">Parcel</a></li>
<li class="mb-2"><a href="/docs/{{ .Site.Params.docs_version }}/getting-started/vite/">Vite</a></li>
</ul>
</div>
<div class="col-6 col-lg-2 mb-3">
@@ -243,10 +243,10 @@ $utilities: map-merge(
<p>Why write more JavaScript when you can write HTML? Nearly all of Bootstrap's JavaScript plugins feature a first-class data API, allowing you to use JavaScript just by adding <code>data</code> attributes.</p>
<div class="p-4 mb-3 border rounded-3">
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-primary dropdown-toggle" type="button" id="dropdown" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdown">
<li><a class="dropdown-item" href="#">Dropdown item</a></li>
<li><a class="dropdown-item" href="#">Dropdown item</a></li>
<li><a class="dropdown-item" href="#">Dropdown item</a></li>
@@ -255,10 +255,10 @@ $utilities: map-merge(
</div>
{{ highlight (printf `<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
<button class="btn btn-primary dropdown-toggle" type="button" id="dropdown" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</button>
<ul class="dropdown-menu">
<ul class="dropdown-menu" aria-labelledby="dropdown">
<li><a class="dropdown-item" href="#">Dropdown item</a></li>
<li><a class="dropdown-item" href="#">Dropdown item</a></li>
<li><a class="dropdown-item" href="#">Dropdown item</a></li>
+4 -5
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
const classes = Array.from(event.target.closest('.bd-code-snippet').querySelector('.bd-example').classList).join(' ')
// 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(' ')
const jsSnippet = event.target.closest('.bd-code-snippet').querySelector('.btn-edit').getAttribute('data-sb-js-snippet')
const jsSnippet = event.target.closest('.bd-code-snippet').querySelector('.btn-edit').getAttribute('data-js-snippet')
StackBlitzSDK.openBootstrapSnippet(htmlSnippet, jsSnippet, classes)
})
})
@@ -42,11 +42,10 @@
<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 m-0 border-0 ${classes}">
<body class="p-3 ${classes}">
<!-- Example Code -->
${htmlSnippet.replace(/^/gm, ' ')}
+5 -6
View File
@@ -4,18 +4,17 @@
`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: ""
* lang: language used to display the code - default: "html"
* show_markup: if the markup should be output in the HTML - default: `true`
* js_snippet: add extra JS snippet to StackBlitz - default: `false`
* 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`
* show_markup: if the markup should be output in the HTML - default: `true`
*/ -}}
{{- $id := .Get "id" -}}
{{- $class := .Get "class" -}}
{{- $lang := .Get "lang" | default "html" -}}
{{- $stackblitz_add_js := .Get "stackblitz_add_js" | default false -}}
{{- $show_markup := .Get "show_markup" | default true -}}
{{- $show_preview := .Get "show_preview" | default true -}}
{{- $show_markup := .Get "show_markup" | default true -}}
{{- $js_snippet := .Get "js_snippet" | default false -}}
{{- $input := .Inner -}}
<div class="bd-example-snippet bd-code-snippet">
@@ -30,7 +29,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 $stackblitz_add_js }} data-sb-js-snippet="{{ $stackblitz_add_js }}"{{ end }} title="Try it on StackBlitz">
<button type="button" class="btn-edit text-nowrap"{{ with $js_snippet }} data-js-snippet="{{ $js_snippet }}"{{ 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">
Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB