Getting Started
Including Bootstrap
Include Bootstrap via CDN for quick start — the CSS goes in the <head>, the JS bundle (which includes Popper) goes before </body>. The bundle.min.js includes Popper for tooltips/dropdowns/popovers. With npm, import the CSS and JS in your entry file. Bootstrap 5 dropped jQuery dependency — all components work with vanilla JS.
<!-- CSS only (in <head>) -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- JS bundle (before </body>) -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- or install via npm -->
<!-- npm install [email protected] -->
<!-- import in JS -->
// import 'bootstrap/dist/css/bootstrap.min.css'
// import 'bootstrap' // imports all JSContainers
Containers are the most basic layout element — they center content and add horizontal padding. .container is fixed-width at each breakpoint (max-width changes); .container-fluid is always 100% wide. Responsive containers (container-sm/md/lg/xl/xxl) are 100% wide until the named breakpoint, then become fixed-width. Use .container for most layouts; .container-fluid for full-width apps.
<!-- fixed-width container (responsive breakpoints) -->
<div class="container">
<!-- content centered with max-width -->
</div>
<!-- full-width container -->
<div class="container-fluid">
<!-- spans entire viewport width -->
</div>
<!-- responsive containers (max-width at breakpoint) -->
<div class="container-sm"> <!-- 100% until sm, then fixed -->
<div class="container-md">
<div class="container-xl">
<!-- 100% wide until the breakpoint, then max-width applied -->
<div class="container-xxl">Responsive Breakpoints
Bootstrap uses a mobile-first, min-width media query system. There are 6 breakpoints: xs (default), sm (576px), md (768px), lg (992px), xl (1200px), xxl (1400px). Classes like col-md-6 apply at md AND above. To show/hide at breakpoints, use d-none (display:none) and d-{breakpoint}-block. This mobile-first approach means you style for small screens first, then add complexity for larger ones.
/* Bootstrap 5 breakpoints (min-width, mobile-first) */
/* xs: <576px (default, no media query needed) */
/* sm: >=576px */
/* md: >=768px */
/* lg: >=992px */
/* xl: >=1200px */
/* xxl: >=1400px */
<!-- classes apply AT and ABOVE the breakpoint -->
<div class="col-12 col-md-6 col-lg-4">
<!-- full width on mobile, half on md, third on lg -->
</div>
<!-- hidden/visible at breakpoints -->
<div class="d-none d-md-block"> <!-- hidden below md -->
<div class="d-block d-md-none"> <!-- visible below md only -->Reboot & Base Styles
Reboot is Bootstrap's CSS reset — it normalizes browser styles using rem units (root em, based on the html font-size of 16px). All elements get box-sizing: border-box. Headings, paragraphs, lists, tables, and links get sensible defaults. Reboot removes top margins from headings and lists, setting them to 0. This gives a consistent baseline across browsers before Bootstrap's components layer on top.
<!-- Reboot normalizes styles: box-sizing, margins, etc. -->
<!-- body gets: font-family, font-size (1rem), line-height (1.5), color -->
<!-- headings use rem units, margin-top removed -->
<h1>Heading 1 (2.5rem)</h1>
<h2>Heading 2 (2rem)</h2>
<!-- links get color and underline on hover -->
<a href="#">Default link</a>
<!-- tables get basic styling -->
<table class="table">...</table>
<!-- <ul>/<ol> have padding-left removed -->
<ul>
<li>Item</li>
</ul>Customizing with CSS Variables
Bootstrap 5 exposes hundreds of CSS custom properties (variables) prefixed with --bs-. Override them in :root to theme your site globally. Dark mode is built-in via data-bs-theme='dark' on the <html> element, which swaps a set of variables. This makes theming much easier than the old Sass-variable approach — you can change colors, fonts, spacing, and radii with plain CSS, no build step needed.
:root {
/* override Bootstrap's CSS variables */
--bs-primary: #0d6efd;
--bs-body-bg: #ffffff;
--bs-body-color: #212529;
--bs-font-sans-serif: 'Inter', system-ui, sans-serif;
--bs-border-radius: 0.375rem;
}
/* dark mode via data attribute */
[data-bs-theme="dark"] {
--bs-body-bg: #212529;
--bs-body-color: #f8f9fa;
}
<!-- use in HTML -->
<div style="background: var(--bs-primary); color: var(--bs-white);">
Custom styled
</div>Layout Basics
Rows & Columns
.row is a flex container (display: flex) with negative horizontal margins to offset column padding. Direct .col children flex equally to fill the row. Specify col-{1-12} for fixed proportions (out of 12). Without a number, .col takes equal remaining space. The 12-column grid is the core of Bootstrap layouts — combine col-{n} and auto .col for flexible layouts.
<!-- .row creates a flex container with negative margins -->
<!-- .col children flex equally -->
<div class="container">
<div class="row">
<div class="col">Column 1</div>
<div class="col">Column 2</div>
<div class="col">Column 3</div>
</div>
<!-- 3 equal columns -->
</div>
<!-- sized columns -->
<div class="row">
<div class="col-8">8/12 width</div>
<div class="col-4">4/12 width</div>
</div>
<!-- auto + sized -->
<div class="row">
<div class="col">auto width (content-based)</div>
<div class="col-6">exactly half</div>
<div class="col">auto width</div>
</div>Gutters (Spacing Between Columns)
Gutters are the padding between columns, controlled by the g-* classes (g-0 to g-5). g-0 removes all gutters (edge-to-edge columns). g-3 is the default. Gutters work both horizontally (between columns) and vertically (between rows when columns wrap). Use responsive variants (g-2 g-md-4) for different spacing at breakpoints. The gutter system replaced the old gutter-only horizontal padding approach.
<!-- default gutters (1.5rem padding on each side of columns) -->
<div class="row">
<div class="col-6">A</div>
<div class="col-6">B</div>
</div>
<!-- remove gutters -->
<div class="row g-0">
<div class="col-6">A</div>
<div class="col-6">B</div>
</div>
<!-- custom gutter sizes: g-0 to g-5 -->
<div class="row g-3">
<div class="col-6">A</div>
<div class="col-6">B</div>
</div>
<!-- responsive gutters -->
<div class="row g-2 g-md-4">
<div class="col-6">A</div>
<div class="col-6">B</div>
</div>
<!-- vertical gutters (row spacing) -->
<div class="row g-3">
<div class="col-12">Row 1</div>
<div class="col-12">Row 2 (g-3 gap above)</div>
</div>Column Wrapping & Alignment
Columns wrap to a new line when their total exceeds 12. Control vertical alignment with align-items-* on the row (start/center/end). Control horizontal distribution with justify-content-* (start/center/end/between/around/evenly). These use flexbox under the hood. Wrapping is automatic — no need for explicit row breaks. This makes masonry-like layouts easy with just col-* classes.
<!-- columns wrap when they exceed 12 total -->
<div class="row">
<div class="col-9">9 cols</div>
<div class="col-4">4 cols → wraps to next line (9+4=13)</div>
<div class="col-6">6 cols (new line)</div>
</div>
<!-- vertical alignment -->
<div class="row align-items-center">
<div class="col">Vertically centered</div>
</div>
<!-- options: align-items-start, -center, -end -->
<div class="row align-items-end">...</div>
<!-- horizontal alignment -->
<div class="row justify-content-center">
<div class="col-6">Centered horizontally</div>
</div>
<!-- options: justify-content-start, -center, -end, -between, -around, -evenly -->Column Ordering
Order classes reorder columns visually without changing HTML. order-first, order-{1-5}, order-last provide 7 levels. Use responsive variants (order-md-first) to change order at breakpoints — useful for SEO (important content first in HTML) while showing it differently on mobile. Offsets (offset-md-4) add left margin to push columns right — useful for centering or indenting. Both rely on flexbox order and margin utilities.
<!-- order classes: order-first, order-{1-5}, order-last -->
<div class="row">
<div class="col order-2">First in HTML, second visually</div>
<div class="col order-1">Second in HTML, first visually</div>
<div class="col order-3">Third in both</div>
</div>
<!-- responsive ordering -->
<div class="row">
<div class="col order-last order-md-first">
Last on mobile, first on desktop
</div>
<div class="col">Normal</div>
</div>
<!-- column offset (push right) -->
<div class="row">
<div class="col-md-4 offset-md-4">Centered (offset 4)</div>
</div>
<!-- offset responsive -->
<div class="col-md-4 offset-md-2 offset-lg-4">...</div>Z-Index & Stacking
Bootstrap uses a z-index scale for stacking: z-1, z-2, z-3 (and negative z-n0, z-n1, z-n2). Components like modals, dropdowns, and tooltips have higher built-in z-index values (1000-1080). For z-index to work, the element needs position (relative, absolute, fixed, or sticky). Avoid arbitrary z-index values — use Bootstrap's scale for consistency. The stacking order is designed so modals always appear above dropdowns, which appear above navbars.
/* Bootstrap's z-index scale */
/* z-1 to z-3, plus z-n0, z-n1, z-n2 for negatives */
<div class="z-3 position-relative">High z-index</div>
<div class="z-1 position-relative">Low z-index</div>
<!-- components have built-in z-index: -->
/* dropdown: 1000 */
/* sticky: 1020 */
/* fixed: 1030 */
/* modal-backdrop: 1050 */
/* modal: 1055 */
/* popover: 1070 */
/* tooltip: 1080 */
<!-- use position utilities for stacking context -->
<div class="position-relative z-3">
Needs position for z-index to apply
</div>Grid System
Basic Grid
Bootstrap's grid is a 12-column system. col-{1-12} specifies how many of the 12 columns an element spans. col-12 = full width, col-6 = half, col-4 = third, col-3 = quarter. Columns within a row should sum to 12 (or less — remaining space is distributed). Without a number, .col divides remaining space equally. The grid uses flexbox — rows are flex containers, columns are flex items.
<!-- 12-column grid -->
<div class="container">
<div class="row">
<div class="col-12">Full width (12/12)</div>
</div>
<div class="row">
<div class="col-6">Half (6/12)</div>
<div class="col-6">Half (6/12)</div>
</div>
<div class="row">
<div class="col-4">Third (4/12)</div>
<div class="col-4">Third (4/12)</div>
<div class="col-4">Third (4/12)</div>
</div>
<div class="row">
<div class="col-3">Quarter (3/12)</div>
<div class="col-9">Three-quarters (9/12)</div>
</div>
</div>Responsive Columns
Responsive column classes (col-sm-*, col-md-*, col-lg-*, col-xl-*, col-xxl-*) apply at that breakpoint AND above (mobile-first). The smallest applicable class wins. col-12 col-md-6 col-lg-4 means: full-width on mobile, half on tablets, third on desktop. row-cols-* sets the number of equal-width columns per row at a breakpoint — simpler than specifying col-* on each child when all columns are equal.
<!-- different widths at different breakpoints -->
<div class="row">
<!-- full on mobile, half on md, third on lg -->
<div class="col-12 col-md-6 col-lg-4">Card 1</div>
<div class="col-12 col-md-6 col-lg-4">Card 2</div>
<div class="col-12 col-md-6 col-lg-4">Card 3</div>
</div>
<!-- mobile-first: base class applies to all, -->
<!-- larger breakpoints override -->
<div class="col-12 col-sm-6 col-md-4 col-lg-3 col-xl-2">
1 per row on xs, 2 on sm, 3 on md, 4 on lg, 6 on xl
</div>
<!-- equal-width columns at breakpoint -->
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3">
<div class="col">Auto-width card</div>
<div class="col">Auto-width card</div>
<div class="col">Auto-width card</div>
</div>Nesting Columns
To nest grids, put a .row inside a .col — the nested row creates a new 12-column context within the parent column's width. The nested columns (col-4, col-8) divide the parent's width, not the full page. Nesting is essential for complex layouts like sidebars with sub-sections. Keep nesting shallow (2-3 levels max) to avoid overly narrow columns and maintain readability.
<!-- nest a row inside a column -->
<div class="row">
<div class="col-6">
<!-- outer column -->
<h3>Left half</h3>
<!-- nested row: new 12-column context -->
<div class="row">
<div class="col-4">Nested 1/3 of parent</div>
<div class="col-8">Nested 2/3 of parent</div>
</div>
</div>
<div class="col-6">
<h3>Right half</h3>
</div>
</div>
<!-- the nested row creates a new 12-col grid -->
<!-- within the parent column's width -->Column Offsets & Margins
offset-{breakpoint}-{n} adds n columns of left margin, useful for centering or indentation. offset-md-4 on a col-md-4 centers it (4 + 4 + 4 = 12). For simpler centering, use mx-auto (margin: 0 auto) which works regardless of column count. Responsive offsets (offset-sm-2 offset-md-0) let you indent on mobile but not desktop. Offsets are cleaner than empty spacer columns.
<!-- offset: add left margin (empty columns) -->
<div class="row">
<div class="col-md-4 offset-md-4">
Centered (4 + 4 offset each side = 12)
</div>
</div>
<!-- offset only on one side -->
<div class="row">
<div class="col-md-6 offset-md-3">
Centered with more left space
</div>
</div>
<!-- responsive offset -->
<div class="row">
<div class="col-sm-8 offset-sm-2 offset-md-0 col-md-12">
Offset on mobile, none on desktop
</div>
</div>
<!-- margin utilities for auto centering -->
<div class="row">
<div class="col-md-6 mx-auto">
Auto-centered (margin: 0 auto)
</div>
</div>Row Columns & Auto Layout
row-cols-{n} sets how many equal-width columns per row — much cleaner than adding col-* to each child when they're all the same width. row-cols-2 means 2 columns per row; items wrap automatically. Responsive variants (row-cols-1 row-cols-md-3) change the count at breakpoints. Plain .col (no number) makes columns divide space equally. Use row-cols for card grids; use col-{n} when columns need specific proportions.
<!-- row-cols: set number of columns per row -->
<div class="row row-cols-2">
<div class="col">Item 1</div>
<div class="col">Item 2</div>
<div class="col">Item 3</div> <!-- wraps to new row -->
<div class="col">Item 4</div>
</div>
<!-- 2 per row automatically -->
<!-- responsive row-cols -->
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4">
<div class="col">Card</div>
<div class="col">Card</div>
<div class="col">Card</div>
<div class="col">Card</div>
</div>
<!-- auto-fit columns: .col without number -->
<div class="row">
<div class="col">Equal</div>
<div class="col">Equal</div>
<div class="col">Equal</div>
</div>
<!-- each takes 1/3, regardless of content -->Typography
Headings & Display
Bootstrap styles h1-h6 with rem-based sizes (h1 = 2.5rem, h6 = 1rem). The .h1-.h6 classes apply heading styles to any element. Display headings (display-1 to display-6) are larger and thinner — for hero sections. .lead makes a paragraph slightly larger and lighter — typically for the first paragraph. Headings have no top margin by default (Reboot removes it) to avoid layout gaps.
<!-- standard headings (h1-h6) -->
<h1>h1 heading</h1>
<h2>h2 heading</h2>
<h3>h3 heading</h3>
<!-- heading classes for matching styles -->
<p class="h1">Looks like h1</p>
<p class="h2">Looks like h2</p>
<!-- display headings (larger, thinner) -->
<h1 class="display-1">Display 1</h1>
<h1 class="display-2">Display 2</h1>
<h1 class="display-3">Display 3</h1>
<h1 class="display-4">Display 4</h1>
<h1 class="display-5">Display 5</h1>
<h1 class="display-6">Display 6</h1>
<!-- lead paragraph -->
<p class="lead">This is a lead paragraph.</p>Inline Text Elements
Bootstrap styles semantic HTML elements: <mark> (highlight), <del>/<s> (strikethrough), <ins>/<u> (underline), <small> (fine print). Text utilities provide styling: text-uppercase/lowercase/capitalize, fw-bold/light/normal, fst-italic, text-muted (gray). text-decoration-underline/line-through control underlines. These utilities are preferred over inline styles for consistency.
<!-- text styling -->
<p>You can use <mark>highlight</mark> text.</p>
<p><del>Deleted</del> and <s>strikethrough</s> text.</p>
<p><ins>Inserted</ins> and <u>underline</u> text.</p>
<p><small>Small text</small> for fine print.</p>
<p><strong>Bold</strong> and <em>italic</em> text.</p>
<!-- text utilities -->
<p class="text-decoration-underline">Underlined</p>
<p class="text-decoration-line-through">Line through</p>
<p class="text-lowercase">lowercase text</p>
<p class="text-uppercase">UPPERCASE TEXT</p>
<p class="text-capitalize">Capitalized Text</p>
<p class="fw-bold">Font weight bold</p>
<p class="fw-light">Font weight light</p>
<p class="fst-italic">Font style italic</p>
<p class="text-muted">Muted/gray text</p>Lists
list-unstyled removes default list styling (bullets and left padding) — useful for navigation menus. list-inline makes list items display inline (for tag clouds, breadcrumbs). Description lists (dl/dt/dd) get horizontal layout with the row class — dt on left, dd on right, aligned via the grid. Lists in Bootstrap have margin-top: 0 and margin-bottom: 1rem for consistent spacing.
<!-- unordered list -->
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<!-- unstyled list (no bullets, no padding) -->
<ul class="list-unstyled">
<li>No bullets</li>
<li>No left padding</li>
</ul>
<!-- inline list -->
<ul class="list-inline">
<li class="list-inline-item">Inline 1</li>
<li class="list-inline-item">Inline 2</li>
<li class="list-inline-item">Inline 3</li>
</ul>
<!-- description list -->
<dl>
<dt>Term</dt>
<dd>Definition</dd>
</dl>
<!-- horizontal description list -->
<dl class="row">
<dt class="col-sm-3">Term</dt>
<dd class="col-sm-9">Definition</dd>
</dl>Blockquotes & Code
Blockquotes use the <figure>/<blockquote>/<figcaption> structure for semantics. blockquote-footer styles the citation. Code styling: <code> for inline code, <pre><code> for code blocks, <kbd> for keyboard keys, <var> for variables. Always HTML-escape angle brackets in code (< for <). Blockquotes can be aligned with text-center/text-end. The kbd styling gives keys a keyboard-like appearance.
<!-- blockquote with source -->
<figure>
<blockquote class="blockquote">
<p>A well-known quote.</p>
</blockquote>
<figcaption class="blockquote-footer">
Someone famous in <cite title="Source Title">Source Title</cite>
</figcaption>
</figure>
<!-- blockquote alignment -->
<blockquote class="blockquote text-center">Centered</blockquote>
<blockquote class="blockquote text-end">Right-aligned</blockquote>
<!-- inline code -->
<p>Use <code><section></code> tag.</p>
<!-- code block -->
<pre><code><div class="container">
Hello
</div>
</code></pre>
<!-- variables -->
<var>y</var> = <var>mx</var> + <var>b</var>
<!-- keyboard input -->
<kbd>Ctrl</kbd> + <kbd>C</kbd>Text Alignment & Wrapping
Text alignment: text-start/center/end (Bootstrap 5 renamed left/right to start/end for RTL support). Responsive variants (text-md-start) change alignment at breakpoints. text-nowrap prevents wrapping; text-truncate adds ellipsis for overflow (needs a max-width or constrained container). text-break breaks long words. lh-* controls line-height. These utilities handle text flow without custom CSS.
<!-- text alignment -->
<p class="text-start">Left aligned (default)</p>
<p class="text-center">Center aligned</p>
<p class="text-end">Right aligned</p>
<!-- responsive alignment -->
<p class="text-center text-md-start">
Center on mobile, left on md+
</p>
<!-- text wrapping -->
<div class="text-wrap">This text wraps.</div>
<div class="text-nowrap">This text doesn't wrap.</div>
<!-- truncate with ellipsis -->
<div class="text-truncate" style="max-width: 200px;">
This long text will be truncated with an ellipsis...
</div>
<!-- word break -->
<p class="text-break">verylongwordwithoutspaces</p>
<!-- line height -->
<p class="lh-1">Line height 1</p>
<p class="lh-sm">Line height small</p>
<p class="lh-base">Line height base (default)</p>
<p class="lh-lg">Line height large</p>Tables
Basic Table
The .table class adds padding, borders, and horizontal dividers. Use <thead> for headers, <tbody> for data. scope='col' on <th> in the header and scope='row' on <th> in rows improve accessibility for screen readers. Tables are opt-in — without .table, you get unstyled HTML tables. Always use semantic table elements (thead, tbody, th, tr, td) for accessibility.
<!-- basic table with styling -->
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Email</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Alice</td>
<td>[email protected]</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Bob</td>
<td>[email protected]</td>
</tr>
</tbody>
</table>Table Variants & Striped
Table modifiers: table-striped (alternating row colors), table-bordered (all borders), table-borderless (no borders), table-hover (row highlight on hover), table-sm (condensed padding), table-dark (dark theme). These can be combined: table table-striped table-hover. The dark variant inverts colors for dark backgrounds. table-sm halves the cell padding for denser data display.
<!-- striped rows -->
<table class="table table-striped">
<!-- alternating background colors -->
</table>
<!-- bordered table -->
<table class="table table-bordered">
<!-- borders on all sides -->
</table>
<!-- borderless table -->
<table class="table table-borderless">
<!-- no borders -->
</table>
<!-- hoverable rows -->
<table class="table table-hover">
<!-- row highlights on hover -->
</table>
<!-- small table -->
<table class="table table-sm">
<!-- condensed padding -->
</table>
<!-- dark table -->
<table class="table table-dark">
<!-- dark background -->
</table>Table Colors
Apply contextual classes to <tr> or <td>: table-primary, table-success, table-danger, table-warning, table-info, table-secondary, table-light, table-dark, table-active. These add subtle background tints for status indication. On dark tables, the same classes provide lighter variants. Use sparingly for meaningful status (success for completed, danger for errors) rather than decoration.
<!-- contextual row/cell colors -->
<table class="table">
<thead>
<tr class="table-primary"><th>Primary header</th></tr>
</thead>
<tbody>
<tr class="table-success">
<td>Success row (green)</td>
</tr>
<tr class="table-danger">
<td>Danger row (red)</td>
</tr>
<tr class="table-warning">
<td>Warning row (yellow)</td>
</tr>
<tr class="table-info">
<td>Info row (cyan)</td>
</tr>
<!-- individual cells -->
<tr>
<td class="table-active">Active cell</td>
<td>Normal cell</td>
</tr>
</tbody>
</table>Responsive Tables
Wrap tables in .table-responsive to enable horizontal scrolling on small screens (prevents layout breakage). table-responsive-sm/md/lg/xl/xxl scroll only below that breakpoint — the table fits normally on larger screens. Without responsive wrapping, wide tables overflow their container. The wrapper div is necessary because overflow can't be applied directly to <table>. Always use this for tables with many columns.
<!-- responsive table (horizontal scroll on small screens) -->
<div class="table-responsive">
<table class="table">
<!-- scrolls horizontally on small screens -->
<thead>...</thead>
<tbody>...</tbody>
</table>
</div>
<!-- responsive at specific breakpoints -->
<div class="table-responsive-sm">
<!-- scrolls below sm -->
</div>
<div class="table-responsive-md">
<!-- scrolls below md -->
</div>
<div class="table-responsive-lg">
<!-- scrolls below lg -->
</div>
<!-- always scrollable -->
<div class="table-responsive">...</div>Table Groups & Captions
caption-top moves the caption above the table (default is below). Captions improve accessibility for screen readers. Style thead/tbody/tfoot separately with table-light/table-dark. Vertical alignment: align-top, align-middle, align-bottom on cells or rows — useful when cells have different content heights. The tfoot element is styled like the thead by default but can be customized.
<!-- caption (accessibility, shown below table by default) -->
<table class="table caption-top">
<caption>List of users</caption>
<thead>
<tr><th>#</th><th>Name</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>Alice</td></tr>
</tbody>
</table>
<!-- table groups for styling -->
<table class="table">
<thead class="table-light">
<tr><th>Light header</th></tr>
</thead>
<tbody>
<tr><td>Body</td></tr>
</tbody>
<tfoot class="table-dark">
<tr><td>Dark footer</td></tr>
</tfoot>
</table>
<!-- vertically aligned cells -->
<tr class="align-middle">
<td class="align-top">Top</td>
<td class="align-middle">Middle</td>
<td class="align-bottom">Bottom</td>
</tr>Forms
Form Controls
form-control styles text inputs, textareas, and file inputs. form-select styles dropdowns. Always pair inputs with <label> elements (with for/id matching) for accessibility. form-label adds appropriate spacing. disabled prevents interaction; readonly shows value without editing. mb-3 (margin-bottom) adds spacing between form groups. The .form-control class applies consistent height, padding, and focus styles.
<!-- text input -->
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control" id="email" placeholder="Enter email">
</div>
<!-- textarea -->
<div class="mb-3">
<label for="bio" class="form-label">Bio</label>
<textarea class="form-control" id="bio" rows="3"></textarea>
</div>
<!-- select -->
<select class="form-select" aria-label="Default select">
<option selected>Open this select menu</option>
<option value="1">One</option>
<option value="2">Two</option>
</select>
<!-- disabled -->
<input class="form-control" type="text" placeholder="Disabled" disabled>
<input class="form-control" type="text" value="Readonly" readonly>Form Grid & Layout
Use the grid system (row/col) to lay out forms. For horizontal forms, pair col-form-label with col-* for label/input alignment. row-cols-lg-auto makes form elements size to their content (inline form) on large screens. align-items-center vertically aligns labels with inputs. The grid gives precise control over form layout at different breakpoints without custom CSS.
<!-- form using grid -->
<div class="row mb-3">
<label for="name" class="col-sm-2 col-form-label">Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="name">
</div>
</div>
<!-- inline form -->
<form class="row row-cols-lg-auto g-3 align-items-center">
<div class="col">
<input class="form-control" placeholder="Email">
</div>
<div class="col">
<input class="form-control" placeholder="Password">
</div>
<div class="col">
<button type="submit" class="btn btn-primary">Sign in</button>
</div>
</form>
<!-- horizontal form with column sizing -->
<form>
<div class="row mb-3">
<label class="col-2 col-form-label">Email</label>
<div class="col-10">
<input class="form-control" type="email">
</div>
</div>
</form>Input Groups
Input groups prepend or append text/buttons to inputs using input-group-text. Common for @ usernames, $ currency, .00 decimals, or search buttons. The input-group wrapper makes the addon and input appear as one connected control. Multiple inputs can share one addon. Buttons inside input groups use btn-outline-* for a connected look. Don't mix input groups with form-floating.
<!-- prepend text -->
<div class="input-group mb-3">
<span class="input-group-text">@</span>
<input type="text" class="form-control" placeholder="Username">
</div>
<!-- append text -->
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Recipient's username">
<span class="input-group-text">@example.com</span>
</div>
<!-- prepend + append -->
<div class="input-group mb-3">
<span class="input-group-text">$</span>
<input type="text" class="form-control">
<span class="input-group-text">.00</span>
</div>
<!-- with button -->
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Search">
<button class="btn btn-outline-secondary" type="button">Go</button>
</div>
<!-- multiple inputs -->
<div class="input-group">
<span class="input-group-text">First and last name</span>
<input type="text" class="form-control">
<input type="text" class="form-control">
</div>Floating Labels
Floating labels animate the label from inside the input to above it when the field is focused or has content. The label must come AFTER the input in HTML. A placeholder attribute is required (even if empty) for the floating behavior. This pattern saves space and looks modern. Don't combine with input-group. Floating labels work with inputs, textareas, and selects. They're a clean alternative to traditional labels for compact forms.
<!-- floating label (label floats up when focused/filled) -->
<div class="form-floating mb-3">
<input type="email" class="form-control" id="floatingInput" placeholder="[email protected]">
<label for="floatingInput">Email address</label>
</div>
<!-- floating textarea -->
<div class="form-floating">
<textarea class="form-control" id="floatingTextarea" placeholder="Leave a comment"></textarea>
<label for="floatingTextarea">Comments</label>
</div>
<!-- floating select -->
<div class="form-floating mb-3">
<select class="form-select" id="floatingSelect">
<option selected>Open this select menu</option>
<option value="1">One</option>
</select>
<label for="floatingSelect">Works with selects</label>
</div>
<!-- note: placeholder is REQUIRED for floating labels -->
<!-- the placeholder="..." must be present -->Validation
Bootstrap provides is-valid and is-invalid classes for validation styling, with valid-feedback and invalid-feedback for messages. The needs-validation class on a form, combined with novalidate (disables browser tooltips), lets you use Bootstrap's validation UI with custom JS. On submit, add was-validated to show all validation states. This works with HTML5 constraints (required, pattern, type) or custom server-side validation.
<!-- server-side validation classes -->
<div class="mb-3">
<label for="username" class="form-label">Username</label>
<input type="text" class="form-control is-valid" id="username" value="valid_user">
<div class="valid-feedback">Looks good!</div>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="email" class="form-control is-invalid" id="email">
<div class="invalid-feedback">Please enter a valid email.</div>
</div>
<!-- no validate on form to disable browser validation -->
<form class="needs-validation" novalidate>
<div class="mb-3">
<input type="text" class="form-control" required>
<div class="invalid-feedback">This field is required.</div>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
<!-- JS: form.classList.add('was-validated') on submit -->Cards
Basic Card
Cards are flexible containers with optional header, body, and footer. card-img-top places an image at the top. card-title, card-subtitle, card-text style content. The width is controlled by the parent grid or a style attribute — cards default to full width. card-header and card-footer are for structured content. Cards replaced Bootstrap 3's panels, wells, and thumbnails with one unified component.
<div class="card" style="width: 18rem;">
<!-- optional image -->
<img src="..." class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<h6 class="card-subtitle mb-2 text-muted">Card subtitle</h6>
<p class="card-text">Some quick example text to build on the card title.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
<!-- card sections -->
<div class="card">
<div class="card-header">Header</div>
<div class="card-body">Body content</div>
<div class="card-footer text-muted">Footer</div>
</div>Card Content Types
Cards can contain various content types: images, text, list groups (use list-group-flush to remove borders and match card edges), and links (card-link adds spacing). Mix and match sections — card-body, list-group, card-header, card-footer — to build the exact card you need. list-group-flush integrates lists seamlessly into cards without double borders. This flexibility makes cards Bootstrap's most versatile component.
<!-- list group inside card -->
<div class="card" style="width: 18rem;">
<div class="card-header">Featured</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">Item 1</li>
<li class="list-group-item">Item 2</li>
<li class="list-group-item">Item 3</li>
</ul>
<div class="card-body">
<a href="#" class="card-link">Card link</a>
<a href="#" class="card-link">Another link</a>
</div>
</div>
<!-- kitchen sink (all content types) -->
<div class="card">
<img src="..." class="card-img-top">
<div class="card-body">
<h5 class="card-title">Title</h5>
<p class="card-text">Text</p>
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">List item</li>
</ul>
<div class="card-body">
<a href="#" class="card-link">Link</a>
</div>
</div>Card Grid & Groups
card-group connects cards with shared borders and equal heights. For responsive card grids, use the grid system: row row-cols-1 row-cols-md-3 g-4 gives 1 column on mobile, 3 on desktop, with gap-4 spacing. Each card goes in a .col. The grid approach is more flexible than card-group — cards can have independent heights, and you control wrapping. Use card-group only when you need connected, equal-height cards.
<!-- card group (cards share border, equal height) -->
<div class="card-group">
<div class="card">
<img src="..." class="card-img-top">
<div class="card-body">
<h5 class="card-title">Card 1</h5>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">Card 2</h5>
</div>
</div>
<div class="card">
<div class="card-body">
<h5 class="card-title">Card 3</h5>
</div>
</div>
</div>
<!-- cards have equal height, connected borders -->
<!-- using grid for responsive card layout -->
<div class="row row-cols-1 row-cols-md-3 g-4">
<div class="col">
<div class="card">...</div>
</div>
<div class="col">
<div class="card">...</div>
</div>
</div>Card Navigation
Add navigation to cards with nav-tabs or nav-pills in the card-header. card-header-tabs and card-header-pills integrate the nav flush with the header edges. Use nav-link active for the current tab, nav-link disabled for inactive. To make tabs functional (switch content), add data-bs-toggle='tab' and tab panes — Bootstrap's JS handles the switching. This pattern is common for dashboards and content cards with multiple views.
<!-- card with nav tabs -->
<div class="card text-center">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<li class="nav-item">
<a class="nav-link active" href="#">Active</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled">Disabled</a>
</li>
</ul>
</div>
<div class="card-body">
<h5 class="card-title">Special title</h5>
<p class="card-text">Content for active tab.</p>
<a href="#" class="btn btn-primary">Go</a>
</div>
</div>
<!-- card with pills -->
<div class="card-header">
<ul class="nav nav-pills card-header-pills">
<li class="nav-item"><a class="nav-link active" href="#">Active</a></li>
</ul>
</div>Card Variants & Overlay
Card color variants: bg-{color} with text-white/text-dark for solid backgrounds; border-{color} with text-{color} for colored borders. card-img-overlay places text over an image (card-img fills the card, overlay content sits on top) — use text-bg-dark for readable text on images. text-center/text-start/text-end control text alignment. For dark image overlays, ensure sufficient contrast between text and image.
<!-- colored card -->
<div class="card text-white bg-primary">
<div class="card-header">Header</div>
<div class="card-body">
<h5 class="card-title">Primary card</h5>
<p class="card-text">Text on colored background.</p>
</div>
</div>
<!-- border colored card -->
<div class="card border-primary">
<div class="card-header border-primary">Header</div>
<div class="card-body text-primary">
<h5 class="card-title">Primary border</h5>
</div>
</div>
<!-- image overlay (text over image) -->
<div class="card text-bg-dark">
<img src="..." class="card-img">
<div class="card-img-overlay">
<h5 class="card-title">Overlay title</h5>
<p class="card-text">Text over the image.</p>
</div>
</div>
<!-- text alignment -->
<div class="card text-center">Centered text</div>
<div class="card text-end">Right-aligned</div>Modals
Basic Modal
Modals are triggered by data-bs-toggle='modal' with data-bs-target matching the modal's id. Structure: modal > modal-dialog > modal-content > modal-header/body/footer. btn-close is the X button (data-bs-dismiss='modal'). fade adds a transition. tabindex='-1' and aria-hidden are for accessibility. The modal is hidden by default and positioned with fixed positioning. Bootstrap JS handles showing, hiding, backdrop, and focus management.
<!-- Button to trigger -->
<button type="button" class="btn btn-primary" data-bs-toggle="modal"
data-bs-target="#exampleModal">
Launch demo modal
</button>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1"
aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"
aria-label="Close"></button>
</div>
<div class="modal-body">
Modal body text goes here.
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>Modal Sizing & Scrolling
Modal sizes: modal-sm, default, modal-lg, modal-xl, modal-fullscreen. modal-fullscreen-{breakpoint}-down is fullscreen only below that breakpoint. modal-dialog-scrollable makes the body scroll (header/footer stay fixed) — essential for long content. modal-dialog-centered vertically centers the modal. These classes go on modal-dialog. Combine them: modal-dialog modal-dialog-centered modal-dialog-scrollable for a centered, scrollable modal.
<!-- sizes -->
<div class="modal-dialog modal-sm">Small</div>
<div class="modal-dialog">Default</div>
<div class="modal-dialog modal-lg">Large</div>
<div class="modal-dialog modal-xl">Extra large</div>
<div class="modal-dialog modal-fullscreen">Fullscreen</div>
<!-- responsive fullscreen -->
<div class="modal-dialog modal-fullscreen-sm-down">
<!-- fullscreen below sm, normal above -->
</div>
<!-- scrollable long content -->
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-body">
<!-- long content scrolls within modal -->
</div>
</div>
</div>
<!-- vertically centered -->
<div class="modal-dialog modal-dialog-centered">
<!-- centered vertically in viewport -->
</div>Modal via JavaScript
Control modals via JS: create an instance with new bootstrap.Modal(el), then show()/hide()/toggle(). backdrop: 'static' prevents closing on backdrop click; keyboard: false disables Esc. Events: show.bs.modal, shown.bs.modal, hide.bs.modal, hidden.bs.modal (show = starting, shown = finished). Use shown.bs.modal to focus an input or load dynamic content. The static backdrop is useful for forms where accidental closure loses data.
<!-- HTML modal (hidden) -->
<div class="modal fade" id="myModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">Dynamic content here</div>
</div>
</div>
</div>
<script>
// create modal instance
const modalEl = document.getElementById('myModal')
const modal = new bootstrap.Modal(modalEl)
// show
modal.show()
// hide
modal.hide()
// toggle
modal.toggle()
// handle events
modalEl.addEventListener('shown.bs.modal', () => {
console.log('modal fully shown')
})
modalEl.addEventListener('hidden.bs.modal', () => {
console.log('modal fully hidden')
})
// pass options
const modal = new bootstrap.Modal(modalEl, {
backdrop: 'static', // don't close on backdrop click
keyboard: false // don't close on Esc
})
</script>Tooltips & Popovers
Tooltips show on hover/focus; popovers show on click. Both need JS initialization (Bootstrap doesn't auto-init for performance). data-bs-placement sets position (top/bottom/left/right). Popovers have title + content; data-bs-html='true' allows HTML. data-bs-trigger='focus' makes popovers dismissible (click outside). Tooltips and popovers use Popper.js (included in the bundle) for smart positioning. They're ideal for hints, definitions, and contextual info.
<!-- tooltip (hover/focus) -->
<button type="button" class="btn btn-secondary" data-bs-toggle="tooltip"
data-bs-placement="top" title="Tooltip on top">
Hover me
</button>
<!-- positions: top, bottom, left, right -->
<button data-bs-toggle="tooltip" data-bs-placement="right"
title="Right tooltip">Right</button>
<!-- popover (click) -->
<button type="button" class="btn btn-lg btn-danger" data-bs-toggle="popover"
title="Popover title" data-bs-content="Content here">
Click to toggle popover
</button>
<!-- popover with HTML content -->
<button data-bs-toggle="popover" data-bs-html="true"
data-bs-content="<b>Bold</b> content">HTML popover</button>
<!-- dismissible popover -->
<button data-bs-toggle="popover" data-bs-trigger="focus"
title="Dismissible">Click outside to dismiss</button>
<script>
// MUST initialize tooltips and popovers
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]')
tooltipTriggerList.forEach(t => new bootstrap.Tooltip(t))
const popoverTriggerList = document.querySelectorAll('[data-bs-toggle="popover"]')
popoverTriggerList.forEach(p => new bootstrap.Popover(p))
</script>Offcanvas (Drawer)
Offcanvas is a slide-in drawer (like a modal but from the edge). offcanvas-start/end/top/bottom sets the slide direction. Structure mirrors modal: offcanvas-header/body with btn-close. data-bs-backdrop='static' prevents closing on backdrop click. text-bg-dark for dark variant. Offcanvas is ideal for mobile navigation, filters, or side panels. Unlike modals, it doesn't cover the full screen — it's an overlay drawer. Replace navbar-collapse with offcanvas for modern mobile menus.
<!-- trigger button -->
<button class="btn btn-primary" data-bs-toggle="offcanvas"
data-bs-target="#demoOffcanvas">
Open offcanvas
</button>
<!-- offcanvas drawer -->
<div class="offcanvas offcanvas-start" tabindex="-1" id="demoOffcanvas">
<div class="offcanvas-header">
<h5 class="offcanvas-title">Title</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas"></button>
</div>
<div class="offcanvas-body">
<p>Content for the offcanvas.</p>
</div>
</div>
<!-- positions: start (left), end (right), top, bottom -->
<div class="offcanvas offcanvas-end" id="rightDrawer">Right side</div>
<div class="offcanvas offcanvas-top" id="topDrawer">Top</div>
<!-- dark variant -->
<div class="offcanvas offcanvas-start text-bg-dark" id="darkDrawer">
Dark offcanvas
</div>
<!-- static backdrop (no close on click outside) -->
<div class="offcanvas" data-bs-backdrop="static">...</div>Alerts
Basic Alerts
Alerts display contextual feedback messages. alert-{variant} sets the color (primary, success, danger, warning, info, light, dark). role='alert' is for screen reader accessibility. alert-link styles links to match the alert color. Use alerts for: form validation feedback, action results (saved! deleted!), or important notices. Choose colors semantically: success for positive, danger for errors, warning for caution, info for neutral info.