# Modus Bootstrap > Powerful, extensible, and feature-packed frontend toolkit. Build and customize with Sass, utilize prebuilt grid system and components, and bring projects to life with powerful JavaScript plugins. --- # Install Modus Bootstrap Source: https://mb.christianoliff.com/docs/6.0/getting-started/install Add Bootstrap to your project with CDN, package manager, or source files. ## Install Pull in Bootstrap’s **source files** into nearly any project with some of the most popular package managers. No matter the package manager, Bootstrap will **require a [Sass compiler]([[docsref:/guides/contribute#sass]]) and [PostCSS]([[docsref:/guides/contribute#postcss]])** for a setup that matches our official compiled versions. Package managed installs don’t include documentation or our full build scripts. You can also [use any demo from our Examples repo](https://github.com/twbs/examples) to quickly jumpstart Bootstrap projects. After installing, head to [our npm guide]([[docsref:/guides/npm]]) for a full setup guide. The [Bootstrap npm package](https://www.npmjs.com/package/bootstrap) is published to npm‘s registry, which pnpm, Yarn, and Bun use. ### Using npm Using `import * as bootstrap from 'bootstrap'` will load all of Bootstrap’s plugins onto a `bootstrap` object. You can also import plugins individually for automatic tree shaking: ```js ``` You can also import plugins directly by loading the `/js/dist/*.js` files under the package’s top-level directory. Bootstrap’s `package.json` contains some additional metadata under the following keys: - `sass` - path to Bootstrap’s main [Sass](https://sass-lang.com/) source file - `style` - path to Bootstrap’s non-minified CSS that’s been compiled using the default settings (no customization) Additionally, Bootstrap ships a `.browserslistrc` file at the package root, which defines browser targets for tools like Browserslist and Autoprefixer. ### Using Yarn Yarn 2+ (aka Yarn Berry) doesn’t support the `node_modules` directory by default, so our [Sass & JS example](https://github.com/twbs/examples/tree/main/sass-js) needs some adjustments: ```sh yarn config set nodeLinker node-modules # Use the node_modules linker touch yarn.lock # Create an empty yarn.lock file yarn install # Install the dependencies yarn start # Start the project ``` ## More packages Other package-managed installs are available as well for Bootstrap as well. [[config:current_ruby_version]]'`, lang: 'bash' }, { label: 'Composer', code: 'composer require twbs/bootstrap:[[config:current_version]]', lang: 'bash' }, { label: 'NuGet', code: `Install-Package bootstrap # Default Install-Package bootstrap.sass # Sass version`, lang: 'powershell' } ]} /> ### Using RubyGems We recommend installing Bootstrap in your Ruby apps using [Bundler](https://bundler.io/), but you can also use [RubyGems](https://rubygems.org/). See [the gem’s README](https://github.com/twbs/bootstrap-rubygem/blob/main/README.md) for further details. ```sh gem Install Modus Bootstrap -v [[config:current_ruby_version]] ``` ### Using NuGet If you develop in .NET Framework, you can also install and manage Bootstrap’s [CSS](https://www.nuget.org/packages/bootstrap/) or [Sass](https://www.nuget.org/packages/bootstrap.sass/) and JavaScript using [NuGet](https://www.nuget.org/). Newer projects should use [libman](https://learn.microsoft.com/en-us/aspnet/core/client-side/libman/) or another method as NuGet is designed for compiled code, not frontend assets. ## CDN Include Bootstrap’s CSS and JavaScript files via CDN. CDNs (Content Delivery Networks) are services that provides copies of libraries for your website. Instead of installing Bootstrap via a package manager, you link to CDN-hosted files in your website. Here are our primary CDN links for CSS and JavaScript: ```html ``` If you prefer to include Floating UI and Vanilla Calendar Pro separately instead of using the bundle, use an import map to resolve the bare module specifiers: ```html ``` | File type | URL | | --- | --- | | CSS | [`[[config:cdn.css]]`]([[config:cdn.css]]) | | JS bundle (with Floating UI and Vanilla Calendar Pro) | [`[[config:cdn.js_bundle]]`]([[config:cdn.js_bundle]]) | ### Using CDNs You can also use the CDN to fetch any of our additional builds. When using CDN links, be sure to use the `integrity` attribute to verify the correct files and versions. These hashes are unique to each file and version of Bootstrap, so when you update to a new version, be sure the `integrity` attribute is also updated. We also include a `crossorigin="anonymous"` attribute to prevent [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) errors. ### Alternative CDNs We recommend [jsDelivr](https://www.jsdelivr.com/) and use it ourselves in our documentation. However, in some cases—like in some specific countries or environments—you may need to use other CDN providers like [cdnjs](https://cdnjs.com/) or [unpkg](https://unpkg.com/). You’ll find the same files on these CDN providers, albeit with different URLs. With cdnjs, you can [use this direct Bootstrap package link](https://cdnjs.com/libraries/bootstrap) to copy and paste ready-to-use HTML snippets for each dist file from any version of Bootstrap. **Security warning** — If the SRI hashes differ for a given file, you shouldn’t use the files from that CDN, because it means that the file was modified by someone else. Note that you should compare same length hashes, e.g. `sha384` with `sha384`, otherwise it’s expected for them to be different. As such, you can use an online tool like [SRI Hash Generator](https://www.srihash.org/) to make sure that the hashes are the same for a given file. Alternatively, assuming you have OpenSSL installed, you can achieve the same from the CLI, for example: ```sh openssl dgst -sha384 -binary bootstrap.min.js | openssl base64 -A ``` ## Download You can also do the old fashioned thing and download Bootstrap manually. Choose between compiled dist (distribution) files or source files. The latter requires some additional tooling to compiled and use Bootstrap in your project. | Type | Description | Link | | --- | --- | --- | | Distribution files | Ready-to-use compiled and minified CSS and JavaScript files. Doesn't include documentation, source files, or dependencies like Floating UI and Vanilla Calendar Pro. | Download | | Source files | Sass, JavaScript, and documentation files for compiling with your own asset pipeline. Requires [Sass compiler]([[docsref:/guides/contribute#sass]]), [Autoprefixer](https://github.com/postcss/autoprefixer), and a JavaScript bundler like [Rollup](https://rollupjs.org/) or [Webpack](https://webpack.js.org/). | Download | Should you require our full set of [build tools]([[docsref:/guides/contribute#tooling-setup]]), they are included for developing Bootstrap and its docs, but they’re likely unsuitable for your own purposes. --- # Using Bootstrap with AI Source: https://mb.christianoliff.com/docs/6.0/getting-started/ai Learn about Bootstrap’s machine-readable docs and skills files for working with LLMs and agentic developer tools. Bootstrap ships resources built for large language models and AI-powered coding tools: machine-readable documentation you can feed to an LLM, and a set of agent skills that walk agents through common Bootstrap tasks step by step. ## LLM-ready docs Our docs are available in a machine-readable format, following the [llms.txt](https://llmstxt.org/) convention. | File | Description | Link | | --- | --- | --- | | `llms.txt` | A curated index of every documentation page with links and descriptions. | [/llms.txt](/llms.txt) | | `llms-full.txt` | The full text of the documentation concatenated into a single file for direct ingestion. | [/llms-full.txt](/llms-full.txt) | ## Skills Bootstrap ships [agent skills](https://github.com/twbs/bootstrap/tree/main/skills) in the `skills/` directory of our repository. Each skill is a `SKILL.md` file—a focused, step-by-step playbook that an agent can follow to complete a specific Bootstrap task, from migrating a project or setting up a new build to authoring a component and customizing our color system. To use one, point your agent at the relevant `SKILL.md` file (or copy it into your project) and describe what you want to do. The skill’s `description` field tells the agent when it applies, and its steps keep the agent aligned with our official guidance. Always review an agent’s changes against the matching documentation. --- # Approach Source: https://mb.christianoliff.com/docs/6.0/getting-started/approach Learn about the guiding principles, strategies, and techniques used to build and maintain Bootstrap so you can more easily customize and extend it yourself. ## Sass & CSS Bootstrap 6 brings with it a new philosophy of using Sass and CSS together to build and customize projects for your specific needs. At a high level: - **Sass is for programmatic configuration —** Think functions, loops, mixins, and more for generative constructs. - **CSS is for visual customization —** CSS variables for visual properties like colors, spacing, typography, etc. Previous major versions have treated Sass as both programmatic and visual customization with CSS variables adding a more complicated, and less complete, secondary layer. This has been greatly improved in v6. On top of that, we use [PostCSS](https://postcss.org/) to [prefix our CSS variables](https://github.com/twbs/postcss-prefix-custom-properties) with the `bs-` prefix and add vendor prefixes to our CSS properties, as appropriate. ### Sass Sass is used for the following: - Import (`@use` and `@forward`) individual stylesheets that compile into CSS. - Manage repetitive snippets of code with mixins and functions. - Toggle global options like `$enable-smooth-scroll`, `$enable-reduced-motion`, etc. - Configure and generate component variants (theme colors, sizes, etc) through Sass maps, loops, and more. - Bulk-generate CSS variables for every tint and shade of our colors. - Manage component token lists (e.g., `$alert-tokens`) and apply them to specific classes. - Power the utilities API to customize and generate utility classes. ### CSS While you can use Sass to customize how Bootstrap looks, the preferred way now is to use CSS variables whenever possible, including when working with Sass. Here’s how we use CSS: - Customize individual global and component tokens like `--bs-border-radius`, `--bs-alert-padding-x`, etc. - Customize token values using Sass’s `with (...tokens)` syntax to override the default values. - Mix colors to generate our tints and shades for each hue. - Use `calc()` for dynamic values based on the value of another token or CSS variable. ### Examples Here’s how we’d use a mix of Sass and CSS to customize Bootstrap. The Sass helps us manage features and gives us access to generative tokens, while the CSS allows us to customize individual tokens and values. In almost all our components, we setup a Sass map of "tokens" that are really just CSS variables. Using this map, we then generate the CSS custom properties on the component’s class. For example, the alert component has a `$alert-tokens` map that is used to generate the CSS custom properties on the `.alert` class. ```scss $alert-tokens: ( --alert-padding-x: 2rem, --alert-border-radius: 1rem, // … ); .alert { @include tokens($alert-tokens); // … } ``` In practice for you and your projects, this means you can use Sass’s module system to override the CSS variables at build-time for a specific component, or even globally. ```scss @use "../node_modules/modus-bootstrap/scss/bootstrap" with ( // Manage global options $enable-smooth-scroll: true, // Modify global tokens $root-tokens: ( --border-radius: .25rem, --spacer: 1.5rem, ), // Modify component tokens $alert-tokens: ( --alert-padding-x: calc(var(--spacer) * 2), --alert-border-radius: 1rem, ), ); ``` Here’s a Sass-specific example, where we cannot use CSS to easily achieve the same result. The following will remove the `text` and `subtle` variants from the `button-variants` map, and override the `button-sizes` map to only include `sm` and `lg` sizes. ```scss @use "../node_modules/modus-bootstrap/scss/bootstrap" with ( // Modify button sizes to remove default `xs` size $button-sizes: ("sm", "lg"), // Remove default `text` and `subtle` button variants with `null` $button-variants: ( "text": null, "subtle": null, ), ); ``` Here’s an example of just using pure CSS to customize a CSS variables from the compiled CSS. Wherever `var(--bs-border-radius)` is used, it will be replaced with the value `.25rem`. ```css :root { --border-radius: .25rem; --spacer: 1.5rem; } ``` ## Modern essentials Bootstrap employs a handful of important global styles and settings geared towards normalizing browser styles, enabling responsive and mobile-first design, and providing a modern foundation to build upon. ### Responsive design Responsive web design is the practice of building a website that responds to the viewport size of the device it’s being viewed on. This is achieved by using range media queries to apply different styles to the website based on the viewport size. ```css @media (width < 768px) { .container { max-width: 100%; } } ``` Bootstrap ships with several responsive tiers or breakpoints that allow you to stack styles on top of each other, from small mobile devices to large desktop screens. This gives you a very flexible and powerful way to build websites that can be optimized for any-sized device. ### HTML5 doctype Bootstrap requires the use of the HTML5 doctype. Without it, you’ll see some funky and incomplete styling. ```html … ``` ### Viewport meta Bootstrap is developed *mobile first*, a strategy in which we optimize code for mobile devices first and then scale up components as necessary using CSS media queries. To ensure proper rendering and touch zooming for all devices, add the responsive viewport meta tag to your ``. ```html … … ``` You can see an example of this in action in [the quick start]([[docsref:/guides/quickstart/]]). ### Box-sizing For more straightforward sizing in CSS, we switch the global `box-sizing` value from `content-box` to `border-box`. This ensures `padding` does not affect the final computed width of an element. On the rare occasion you need to override it, use something like the following: ```css .your-selector { box-sizing: content-box; } ``` Learn more about [box model and sizing at CSS Tricks](https://css-tricks.com/box-sizing/). ### Reboot For improved cross-browser rendering, we use [Reboot]([[docsref:/content/reboot]]) to correct inconsistencies across browsers and devices while providing slightly more opinionated resets to common HTML elements. ### Browser support You can find our supported range of browsers and their versions [in our `.browserslistrc` file]([[config:repo]]/blob/v[[config:current_version]]/.browserslistrc): If you installed Modus Bootstrap via npm, you can also find this file locally at `node_modules/modus-bootstrap/.browserslistrc`. We use [Autoprefixer](https://github.com/postcss/autoprefixer) to handle intended browser support via CSS prefixes, which uses [Browserslist](https://github.com/browserslist/browserslist) to manage these browser versions. Consult their documentation for how to integrate these tools into your projects. ## Guiding principles Beyond what Bootstrap does, here’s *why* we do it—our philosophy for building on the web. At a high level, here’s what guides our approach: - Components should be responsive and mobile-first - Components should be built with a base class and extended via modifier classes - Component states should obey a common `z-index` scale - Prefer an HTML and CSS implementation over JavaScript - Use utilities over custom styles - Avoid enforcing strict HTML requirements (immediate children selectors) These rules cannot always be followed to the letter, but we strive to follow them as much as possible. ### Responsive Modus Bootstrap’s styles are mobile-first—we add styles as the viewport grows rather than overriding them as it shrinks. Not every component must be fully responsive, but this approach reduces CSS overrides. We use range media queries (`width >= 768px`, for example) to apply styles at a specific breakpoint and carry up through the larger breakpoints. For example, a `.d-none` applies from `min-width: 0` to infinity. On the other hand, a `.md:d-none` applies from the medium breakpoint and up. ### Classes Aside from [Reboot]([[docsref:/content/reboot]]), we strive to use only classes as selectors. Where we can, we avoid type selectors and extraneous parent selectors for greater flexibility. Components are typically built with a base class for shared property-value pairs. For example, `.btn`, `.btn-solid`, and `.theme-primary`. We use `.btn` for all the common styles like `display`, `padding`, and `border-width`. We then use variant and theme modifiers like `.btn-solid.theme-primary` to add more styles. This reduces complexity, streamlines code, and makes for more scalable systems. ### z-index scales We use two `z-index` scales in Bootstrap—elements within a component and overlay components. Some components in Bootstrap are built with overlapping elements to prevent double borders without modifying the `border` property. For example, button groups, input groups, and pagination. These components share a standard `z-index` scale of `0` through `3`, matching our expectations of highest user priority. - `0` is for default states (initial, not actually set) - `1` is for `:hover`, lowest because while it indicates user intent, nearly *anything* can be hovered. - `2` is for `:active`/`.active`, second highest because they indicate state. - `3` is for `:focus`, highest because focused elements are in view and at the user’s attention. Components built with overlays also have a predefined z-index scale, beginning at `1000`. This starting number was chosen arbitrarily and serves as a small buffer between our styles and your project’s custom styles. Each overlay component increases its `z-index` value slightly in such a way that common UI principles allow user focused or hovered elements to remain in view at all times. For example, a modal dialog is document blocking (e.g., you cannot take any other action save for the dialog’s action), so we put that above our navbars. Learn more about this in our [`z-index` layout page]([[docsref:/layout/z-index]]). ### HTML and CSS over JS Whenever possible, we prefer HTML and CSS over JavaScript—they’re more accessible to people of all experience levels and faster in the browser. That’s why our first-class JavaScript API is `data` attributes—it lets you write more HTML instead of JavaScript. Read more in [our JavaScript overview]([[docsref:/getting-started/javascript#data-attributes]]). Our styles build on fundamental browser behaviors. For example, while you can put `.btn` on nearly any element, we prefer ` ``` Components that don’t depend on Floating UI (like Toast, Alert, Collapse, etc.) can be imported individually without any import map: ```html ``` ## Dependencies Some plugins and CSS components depend on other plugins. If you include plugins individually, make sure to check for these dependencies in the docs. Our menus, popovers, and tooltips also depend on [Floating UI](https://floating-ui.com/). Our datepicker also depends on [Vanilla Calendar Pro](https://vanilla-calendar.pro/). ## Data attributes Nearly all Bootstrap plugins can be enabled and configured through HTML alone with data attributes (our preferred way of using JavaScript functionality). Be sure to **only use one set of data attributes on a single element** (e.g., you cannot trigger a tooltip and dialog from the same button.) ## Selectors We use the native `querySelector` and `querySelectorAll` methods to query DOM elements for performance reasons, so you must use [valid selectors](https://www.w3.org/TR/CSS21/syndata.html#value-def-identifier). If you use special selectors like `collapse:Example`, be sure to escape them. ## Events Bootstrap provides custom events for most plugins' unique actions. Generally, these come in an infinitive and past participle form - where the infinitive (ex. `show`) is triggered at the start of an event, and its past participle form (ex. `shown`) is triggered on the completion of an action. All infinitive events provide [`preventDefault()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) functionality. This provides the ability to stop the execution of an action before it starts. Returning false from an event handler will also automatically call `preventDefault()`. ```js const myDialog = document.querySelector('#myDialog') myDialog.addEventListener('show.bs.dialog', event => { return event.preventDefault() // stops dialog from being shown }) ``` ## Programmatic API All constructors accept an optional options object or nothing (which initiates a plugin with its default behavior): ```js const myDialogEl = document.querySelector('#myDialog') const dialog = new bootstrap.Dialog(myDialogEl) // initialized with defaults const configObject = { keyboard: false } const dialog1 = new bootstrap.Dialog(myDialogEl, configObject) // initialized with no keyboard ``` If you’d like to get a particular plugin instance, each plugin exposes a `getInstance` method. For example, to retrieve an instance directly from an element: ```js bootstrap.Popover.getInstance(myPopoverEl) ``` This method will return `null` if an instance is not initiated over the requested element. Alternatively, `getOrCreateInstance` can be used to get the instance associated with a DOM element, or create a new one in case it wasn’t initialized. ```js bootstrap.Popover.getOrCreateInstance(myPopoverEl, configObject) ``` In case an instance wasn’t initialized, it may accept and use an optional configuration object as second argument. ### CSS selectors in constructors In addition to the `getInstance` and `getOrCreateInstance` methods, all plugin constructors can accept a DOM element or a valid [CSS selector](#selectors) as the first argument. Plugin elements are found with the `querySelector` method since our plugins only support a single element. ```js const dialog = new bootstrap.Dialog('#myDialog') const menu = new bootstrap.Menu('[data-bs-toggle="menu"]') const drawer = bootstrap.Drawer.getInstance('#myDrawer') const alert = bootstrap.Alert.getOrCreateInstance('#myAlert') ``` ### Promises and transitions All programmatic API methods are **asynchronous** and return to the caller once the transition is started, but **before it ends**. Methods that show or hide a component return a **promise**. The promise resolves when the transition ends, so you can `await` the method instead of listening for an event. ```js const collapse = bootstrap.Collapse.getOrCreateInstance('#myCollapse') await collapse.show() // The collapsible area is now expanded ``` These methods return a promise: | Method | Components | | --- | --- | | `show`, `hide`, `toggle` | Collapse, Combobox, Datepicker, Dialog, Drawer, Menu, Popover, Tooltip | | `show`, `hide` | Toast | | `show` | Tab | | `close` | Alert | The promise resolves with no value. It resolves at the same moment the matching `shown.bs.*`, `hidden.bs.*`, or `closed.bs.*` event fires, so both styles run your code at the same time. Use the event when you must react to every change, including ones your own code did not start. ```js const drawerEl = document.querySelector('#myDrawer') const drawer = bootstrap.Drawer.getOrCreateInstance(drawerEl) // Await the method you called… await drawer.hide() saveState() // …or listen for every hide, whoever started it drawerEl.addEventListener('hidden.bs.drawer', () => { saveState() }) ``` Because each method returns a promise, you can run steps in order without nesting listeners. ```js const dialog = bootstrap.Dialog.getOrCreateInstance('#myDialog') const toast = bootstrap.Toast.getOrCreateInstance('#myToast') await dialog.hide() await toast.show() ``` The promise also resolves when the call does nothing — for example when the component is already open, when a listener calls `preventDefault()` on the `show.bs.*` event, or when you dispose the component mid-transition. `await` therefore never hangs, but it also does not tell you whether the state changed. Check the state yourself when that matters. In addition, a method call on a **transitioning component will be ignored**. For the promise-returning methods above, such a call resolves immediately. It does not wait for the running transition to end. ```js const myCarouselEl = document.querySelector('#myCarousel') const carousel = bootstrap.Carousel.getInstance(myCarouselEl) // Retrieve a Carousel instance myCarouselEl.addEventListener('slid.bs.carousel', event => { carousel.to('2') // Will slide to the slide 2 as soon as the transition to slide 1 is finished }) carousel.to('1') // Will start sliding to the slide 1 and returns to the caller carousel.to('2') // !! Will be ignored, as the transition to the slide 1 is not finished !! ``` #### `dispose` method Do not call `dispose` immediately after `hide()`. The hide transition is still running at that point, so the component tears down mid-transition. Await the promise first: ```js const toast = bootstrap.Toast.getInstance('#myToast') await toast.hide() toast.dispose() ``` The event-based equivalent also works: ```js const myToast = document.querySelector('#myToast') const toast = bootstrap.Toast.getInstance(myToast) myToast.addEventListener('hidden.bs.toast', () => { toast.dispose() }) toast.hide() ``` ### Default settings You can change the default settings for a plugin by modifying the plugin’s `Constructor.Default` object: ```js // changes default for the toast plugin's `autohide` option to false bootstrap.Toast.Default.autohide = false ``` ## Methods and properties Every Bootstrap plugin exposes the following methods and static properties. | Method | Description | | --- | --- | | `dispose` | Destroys an element’s plugin instance. (Removes stored data on the DOM element) | | `getInstance` | *Static* method which allows you to get the plugin instance associated with a DOM element. | | `getOrCreateInstance` | *Static* method which allows you to get the plugin instance associated with a DOM element, or create a new one in case it wasn’t initialized. | | Static property | Description | | --- | --- | | `NAME` | Returns the plugin name. (Example: `bootstrap.Tooltip.NAME`) | | `VERSION` | The version of each of Bootstrap’s plugins can be accessed via the `VERSION` property of the plugin’s constructor (Example: `bootstrap.Tooltip.VERSION`) | ## Sanitizer Some JavaScript components can render or accept arbitrary HTML in their configuration. To prevent cross-site scripting (XSS) attacks, these components use our built-in content sanitizer to sanitize any options which accept HTML before they are rendered to the page. Content sanitization is enabled by default. In particular: - Popovers and Tooltips can render arbitrary HTML to the page if configured to do so. - Chips and Nav overflow can accept HTML for their icon options (`dismissIcon`, `moreIcon`, and `[data-bs-overflow-icon]`). The tags and attributes allowed by default for tooltip and popover content are as follows. Any tags or attributes not explicitly allowed will be removed during sanitization: Icon options use a separate, tighter allowlist that covers the default SVG icons and common inline-icon markup: **Exercise caution when using these advanced options.** Refer to [OWASP’s Cross Site Scripting Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html) for more information. Vulnerabilities caused solely by disabling or modifying content sanitization are not considered within scope for Bootstrap’s security model. You can add new values to this default `allowList`: ```js const myDefaultAllowList = bootstrap.Tooltip.Default.allowList // To allow table elements myDefaultAllowList.table = [] // To allow td elements and data-bs-option attributes on td elements myDefaultAllowList.td = ['data-bs-option'] // You can push your custom regex to validate your attributes. // Be careful about your regular expressions being too lax const myCustomRegex = /^data-my-app-[\w-]+/ myDefaultAllowList['*'].push(myCustomRegex) ``` You can also replace our sanitizer with a dedicated library, for example [DOMPurify](https://www.npmjs.com/package/dompurify): ```js const yourTooltipEl = document.querySelector('#yourTooltip') const tooltip = new bootstrap.Tooltip(yourTooltipEl, { sanitizeFn(content) { return DOMPurify.sanitize(content) } }) ``` ## Disabled JavaScript Bootstrap’s plugins have no special fallback when JavaScript is disabled. If you care about the user experience in this case, use [`