Skip to content

Migrating to Bootstrap v5 from v3 #600

@cwhite911

Description

@cwhite911

We have ad-hoc started the process of migrating to Bootstrap v5 from Bootstrap v3. Overall, I think updating to Bootstrap 5 is good, however, this mixing of dependencies has caused quite a few breaking changes on the site placing us in a bit of a triage mode.

Related open Issues and PRs:

My suggestion to resolve is to quickly get PRs

merged to normalize dependencies and finalize the switch to Bootstrap 5. We can then migrate old Bootstrap 3 and sometime 4 references safely.

Here are the migration guidelines from:

Here are the big breaking changes

  • Dropped jQuery.
  • Upgraded from Popper v1.x to Popper v2.x.
  • Replaced Libsass with Dart Sass as our Sass compiler given Libsass was deprecated.

Suggested Issues

  1. Inventory current Bootstrap usage and version conflicts
  • Audit templates and partials to identify Bootstrap 3/4 classes, data attributes, and JS usage.
  • Key Bootstrap 3/4 patterns currently in the theme:
    • jQuery + Bootstrap bundle loaded together in head: head.html (jquery.slim.min.js, bootstrap.bundle.min.js concatenated), implying reliance on jQuery-based data-API.
    • Navbar uses BS3/4 attributes and classes: navigation.html (data-toggle, data-target, .navbar-toggler, .navbar-collapse, .navbar-nav, .dropdown-menu), and uses ml-auto (BS4 spacing).
    • Tabs use BS4 data-API: tabs.html (data-toggle="tab", .nav-tabs, .tab-pane, .fade, .show).
    • Collapse/Accordion usage with BS3 data-API: script.js ($("#news .panel-collapse:first").collapse();) and gallery toggler uses jQuery events.
    • Grid classes with BS3/4 naming: multiple layouts (e.g., allnews.html, index.html, team.html, list.html) use .col-lg-, .col-sm-, .row, .container; spacing utilities like .mt-5, .mb-4 (BS4 utility naming).
    • Buttons use BS3/4 classes: theme.md demonstrates .btn, .btn-primary, .btn-outline-*, .btn-link, .btn-warning, etc.
    • Legacy helpers visible: .pull-right in data.html and os.html; .navbar padding overrides in style.css.
    • Dropdowns in brand download partial use .dropdown-menu, .dropdown-item, .dropdown-header: brandDownloadIconDropdownButton.html.
    • Carousel uses BS3/4 classes: index.html (carousel, carousel-item, carousel-indicators).
    • Form/tab JS initialization relies on jQuery .tab('show'): script.js download tab handler.

These locations indicate active BS3/4-era data attributes (data-toggle, data-target), jQuery plugin calls (.collapse(), .tab('show')), and class names (glyph-like .pull-right, ml-auto).

  1. Standardize Bootstrap 5 asset loading
  • Replace concatenated vendor bundle using jQuery + legacy bootstrap.bundle.min.js with a single Bootstrap 5 bundle import.
  • Remove jQuery dependency if not otherwise required.
  1. Migrate navigation components to Bootstrap 5
  • Update .navbar-, .navbar-toggle, .navbar-default patterns to .navbar-expand-, .navbar-toggler, and BS5 data attributes.
  • Check custom nav partials: navigation.html (and other layout files that embed it: e.g., list.html, index.html).
  1. Update grid and spacing utilities
  • Replace deprecated .row-fluid, .col-xs-, .col-sm- patterns with BS5 grid classes; swap .offset-/.pull-/.push-* with offset-* and flex utilities.
  • Ensure custom spacing classes in style.css don’t conflict with BS5.
  1. Migrate forms to Bootstrap 5
  • Update .form-group, .form-control-static, .input-group-addon, .custom-* to BS5 equivalents.
    • I search for them with

rg --no-heading -n "form-group|form-control|input-group|custom-" .

./themes/grass/assets/css/style.css:1081:.form-control {
./themes/grass/assets/css/style.css:1087:.form-control:focus {
./themes/grass/assets/css/style.css:1091:textarea.form-control {
./themes/grass/layouts/contribute/devel.html:42:                <li><i class="fa fa-file-code"></i> &#160;<a href="https://github.com/wenzeslaus/foss4g-2022-developing-custom-grass-tools" target="_blank">Write your own tools</a></li>
./content/about/theme.md:1141:<span class="custom-span">This is a custom span.</span>
./content/about/theme.md:1144:<span class="custom-span">This is a custom span.</span>
  • Ensure validation classes use .is-valid/.is-invalid.
  1. Update components: dropdowns, modals, tooltips, popovers, carousels
  • Replace data-toggle/data-target with data-bs-toggle/data-bs-target.

rg -no-heading -n "data-toggle|data-target|custom-" .

./content/about/history.md:16:<h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#accordion" href="#eighties" aria-expanded="true" aria-controls="eighties">The eighties</a></h4>
./content/about/history.md:51:<h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#nineties" aria-expanded="false" aria-controls="nineties">The nineties</a></h4>
./content/about/history.md:78:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#millennium" aria-expanded="false" aria-controls="millennium">The new millennium</a></h4>
./content/about/history.md:107:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#tens" aria-expanded="false" aria-controls="millennium">The 2010s and beyond</a></h4>
./content/about/theme.md:1141:<span class="custom-span">This is a custom span.</span>
./content/about/theme.md:1144:<span class="custom-span">This is a custom span.</span>
./content/about/history/web-evolution.md:16:          <h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#accordion" href="#1997" aria-expanded="true" aria-controls="1997">1997</a></h4>
./content/about/history/web-evolution.md:43:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1998" aria-expanded="false" aria-controls="1998">1998</a></h4>
./content/about/history/web-evolution.md:69:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1999" aria-expanded="false" aria-controls="1999">1999</a></h4>
./content/about/history/web-evolution.md:110:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2000" aria-expanded="false" aria-controls="2000">2000</a></h4>
./content/about/history/web-evolution.md:152:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2001" aria-expanded="false" aria-controls="2001">2001</a></h4>
./content/about/history/web-evolution.md:194:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2002" aria-expanded="false" aria-controls="2002">2002</a></h4>
./content/about/history/web-evolution.md:236:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2012" aria-expanded="false" aria-controls="2012">2012</a></h4>
./content/about/history/web-evolution.md:277:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2019" aria-expanded="false" aria-controls="2019">2019</a></h4>
./content/about/history/web-evolution.md:304:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2020" aria-expanded="false" aria-controls="2020">2020</a></h4>
./content/about/history/releases.md:17:          <h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#accordion" href="#2025" aria-expanded="true" aria-controls="2025">2025</a></h4>
./content/about/history/releases.md:35:          <h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#accordion" href="#2024" aria-expanded="true" aria-controls="2024">2024</a></h4>
./content/about/history/releases.md:55:          <h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#accordion" href="#2023" aria-expanded="true" aria-controls="2023">2023</a></h4>
./content/about/history/releases.md:80:          <h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#accordion" href="#2022" aria-expanded="true" aria-controls="2022">2022</a></h4>
./content/about/history/releases.md:101:          <h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#accordion" href="#2021" aria-expanded="true" aria-controls="2021">2021</a></h4>
./content/about/history/releases.md:118:          <h4 class="panel-title"><a role="button" data-toggle="collapse" data-parent="#accordion" href="#2020" aria-expanded="true" aria-controls="2020">2020</a></h4>
./content/about/history/releases.md:135:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2019" aria-expanded="false" aria-controls="2019">2019</a></h4>
./content/about/history/releases.md:157:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2018" aria-expanded="false" aria-controls="2018">2018</a></h4>
./content/about/history/releases.md:177:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2017" aria-expanded="false" aria-controls="2017">2017</a></h4>
./content/about/history/releases.md:195:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2016" aria-expanded="false" aria-controls="2016">2016</a></h4>
./content/about/history/releases.md:219:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2015" aria-expanded="false" aria-controls="2015">2015</a></h4>
./content/about/history/releases.md:244:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2014" aria-expanded="false" aria-controls="2014">2014</a></h4>
./content/about/history/releases.md:261:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2013" aria-expanded="false" aria-controls="2013">2013</a></h4>
./content/about/history/releases.md:277:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2012" aria-expanded="false" aria-controls="2012">2012</a></h4>
./content/about/history/releases.md:295:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2011" aria-expanded="false" aria-controls="2011">2011</a></h4>
./content/about/history/releases.md:313:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2010" aria-expanded="false" aria-controls="2010">2010</a></h4>
./content/about/history/releases.md:330:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2009" aria-expanded="false" aria-controls="2009">2009</a></h4>
./content/about/history/releases.md:348:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2008" aria-expanded="false" aria-controls="2008">2008</a></h4>
./content/about/history/releases.md:369:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2007" aria-expanded="false" aria-controls="2007">2007</a></h4>
./content/about/history/releases.md:391:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2006" aria-expanded="false" aria-controls="2006">2006</a></h4>
./content/about/history/releases.md:422:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2005" aria-expanded="false" aria-controls="2005">2005</a></h4>
./content/about/history/releases.md:443:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2004" aria-expanded="false" aria-controls="2004">2004</a></h4>
./content/about/history/releases.md:460:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2003" aria-expanded="false" aria-controls="2003">2003</a></h4>
./content/about/history/releases.md:478:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2002" aria-expanded="false" aria-controls="2002">2002</a></h4>
./content/about/history/releases.md:496:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2001" aria-expanded="false" aria-controls="2001">2001</a></h4>
./content/about/history/releases.md:514:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#2000" aria-expanded="false" aria-controls="2000">2000</a></h4>
./content/about/history/releases.md:534:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1999" aria-expanded="false" aria-controls="1999">1999</a></h4>
./content/about/history/releases.md:561:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1998" aria-expanded="false" aria-controls="1998">1998</a></h4>
./content/about/history/releases.md:596:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1997" aria-expanded="false" aria-controls="1997">1997</a></h4>
./content/about/history/releases.md:611:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1996" aria-expanded="false" aria-controls="1996">1996</a></h4>
./content/about/history/releases.md:627:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1995" aria-expanded="false" aria-controls="1995">1995</a></h4>
./content/about/history/releases.md:643:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1993" aria-expanded="false" aria-controls="1993">1993</a></h4>
./content/about/history/releases.md:658:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1991" aria-expanded="false" aria-controls="1991">1991</a></h4>
./content/about/history/releases.md:674:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1990" aria-expanded="false" aria-controls="199 0">1990</a></h4>
./content/about/history/releases.md:689:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1989" aria-expanded="false" aria-controls="1989">1989</a></h4>
./content/about/history/releases.md:704:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1988" aria-expanded="false" aria-controls="1988">1988</a></h4>
./content/about/history/releases.md:719:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1987" aria-expanded="false" aria-controls="1987">1987</a></h4>
./content/about/history/releases.md:734:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1986" aria-expanded="false" aria-controls="1986">1986</a></h4>
./content/about/history/releases.md:749:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1985" aria-expanded="false" aria-controls="1985">1985</a></h4>
./content/about/history/releases.md:765:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1984" aria-expanded="false" aria-controls="1984">1984</a></h4>
./content/about/history/releases.md:780:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1983" aria-expanded="false" aria-controls="1983">1983</a></h4>
./content/about/history/releases.md:795:          <h4 class="panel-title"><a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion" href="#1982" aria-expanded="false" aria-controls="1982">1982</a></h4>
./themes/grass/layouts/about/team.html:111:        <button class="btn btn-primary" type="button" data-toggle="collapse" data-target="#collapseFormerPSCMembers" aria-expanded="false" aria-controls="collapseFormerPSCMembers">
./themes/grass/layouts/partials/brandDownloadIconDropdownButton.html:52:                data-toggle="dropdown"
./themes/grass/layouts/partials/brandDownloadIconDropdownButton.html:143:                data-toggle="dropdown"
./themes/grass/layouts/partials/brandDownloadIconDropdownButton.html:185:                data-toggle="dropdown"
./themes/grass/layouts/download/tabs.html:29:              <a class="nav-link active" id="linux-tab" data-toggle="tab" href="#linux" role="tab" aria-controls="linux" aria-selected="true">Linux</a>
./themes/grass/layouts/download/tabs.html:32:              <a class="nav-link" id="mac-tab" data-toggle="tab" href="#mac" role="tab" aria-controls="mac" aria-selected="false">macOS</a>
./themes/grass/layouts/download/tabs.html:35:              <a class="nav-link" id="windows-tab" data-toggle="tab" href="#windows" role="tab" aria-controls="windows" aria-selected="false">Windows</a>
./themes/grass/layouts/download/tabs.html:38:                <a class="nav-link" id="windows-tab" data-toggle="tab" href="#docker" role="tab" aria-controls="docker" aria-selected="false">Docker</a>
./themes/grass/layouts/download/tabs.html:68:                    <button class="btn btn-secondary" type="button" data-toggle="collapse" data-target="#collapseWindowsAdditionalOptions" aria-expanded="false" aria-controls="collapseWindowsAdditionalOptions">
./themes/grass/layouts/contribute/devel.html:42:                <li><i class="fa fa-file-code"></i> &#160;<a href="https://github.com/wenzeslaus/foss4g-2022-developing-custom-grass-tools" target="_blank">Write your own tools</a></li>
./themes/grass/layouts/partials/navigation.html:12:        data-target="#navigation"
./themes/grass/layouts/partials/navigation.html:13:        data-toggle="collapse"
./themes/grass/layouts/partials/navigation.html:25:                    data-toggle="dropdown"
./themes/grass/layouts/shortcodes/donateDialog.html:5: <button  data-toggle="modal" data-target="#donateToGrassModal" style="background:none;border:none;padding:0;margin:0;">
  • Verify JS initialization matches BS5.
  1. Replace glyphicons and legacy icon hooks
  • Remove any Bootstrap 3 glyphicon references; ensure Font Awesome is used consistently.
  • Files: search in layouts and style.css for glyphicon.
  1. Adapt utilities and helpers
  • Replace .pull-, .center-block, .img-responsive, .hidden-, .visible-* with BS5 display utilities and .img-fluid.

rg --no-heading -n "\b(pull-[\w-]+|center-block|img-responsive|hidden-[\w-]+|visible-[\w-]+)\b" .

./content/learn/gallery.md:14:<a href="#" class="gallery-toggler pull-right">View more</a>
./content/learn/gallery.md:20:{{< gallery dir="/images/gallery/vector/" />}}<a href="#" class="gallery-toggler pull-right">View more</a>
./content/learn/gallery.md:26:{{< gallery dir="/images/gallery/raster/" />}}<a href="#" class="gallery-toggler pull-right">View more</a>
./content/learn/gallery.md:32:{{< gallery dir="/images/gallery/3D/" />}}<a href="#" class="gallery-toggler pull-right">View more</a>
./content/learn/gallery.md:38:{{< gallery dir="/images/gallery/lidar/" />}}<a href="#" class="gallery-toggler pull-right">View more</a>
./content/learn/gallery.md:44:{{< gallery dir="/images/gallery/remote_sensing/" />}}<a href="#" class="gallery-toggler pull-right">View more</a>
./content/learn/gallery.md:50:{{< gallery dir="/images/gallery/cartography/" />}}<a href="#" class="gallery-toggler pull-right">View more</a>
./themes/grass/layouts/partials/logo.html:2:<img src="{{.Site.BaseURL}}/images/logos/grass-logo/grass-green.svg" class="img-responsive" alt="GRASS">
./themes/grass/layouts/download/os.html:24:	<img src="{{.Site.BaseURL}}/images/logos/grass-{{.Title}}.jpg" width="110" class="pull-right">
./content/about/governance.md:96:<i class="fa fa-code-pull-request fa-7x"
./themes/grass/layouts/download/data.html:23:	<img src="{{.Site.BaseURL}}/images/logos/grass-SampleData.jpg" class="pull-right">
./themes/grass/assets/css/style.css:1045:.ui-helper-hidden-accessible {
  • Verify custom helper classes in style.css for overlaps.
  1. Update tables and cards
  • Migrate .table-condensed/.table-hover variations to BS5 semantics; ensure .card usage matches BS5 (if any legacy .panel-* exist, rewrite to .card).
  • Search layouts for panel/well classes (e.g., allnews.html).

rg --no-heading -n 'class="[^"]*\b(table-(condensed|hover)|panel-[\w-]+|well|card)\b[^"]*"' .

The command produces a lot of output but here is the general summary.

  • Cards: used in brandColor shortcode (color swatch), grass-download partial (card-text), and multiple quicklinks cards.
  • Legacy panels/accordions (BS3): extensive panel-group, panel panel-default, panel-heading, panel-title, panel-collapse, panel-body with data-toggle="collapse" across:
    • history.md
    • releases.md
    • web-evolution.md
  • No table-condensed/table-hover or well hits in these results.
  1. Purge deprecated JS plugins and data-API patterns
  • Ensure no reliance on BS3-only JS behaviors; move to BS5 bundle.
  • Remove any manual $.fn.* Bootstrap plugin calls; replace with BS5 bootstrap.* API if still needed.

rg --no-heading -n '\$\.fn\.' .

./themes/grass/assets/js/script.js:5:    $.fn.lastWord = function() {
  1. Rebuild and fingerprint assets
  • After migration, rebuild Hugo pipelines for CSS/JS bundles and verify integrity hashes in head.html.
  • Confirm no mixed versions remain in the final public output.
  1. Regression pass and browser testing
  • Add a checklist for visual QA (nav, forms, carousel, dropdowns, modals) across key pages: home, news listing, about pages (e.g., roadmap.html), learn pages (e.g., overview.html), and contribute pages (e.g., list.html).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingenhancementNew feature or requesthelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions