javascripttabsbootstrap-5fade

How can I add a fade out effect to the active tab-pane?


I'm using basic Bootstrap 5.3 with the basic pills and tab structure. How can I simply add a fadeOut to the active tab before the fadeIn of the selected tab?

It seems like adding the "fade" class only adds a fadeIn, I want the active tab to slowly disappear before.

The only way I have found so far is to override the whole mechanism and do a jQuery fadeout fadein. I wish I could use more standard code...

Can some please help?

Thanks!

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">

<ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
  <li class="nav-item" role="presentation">
    <button class="nav-link active" id="pills-home-tab" data-bs-toggle="pill" data-bs-target="#pills-home" type="button" role="tab" aria-controls="pills-home" aria-selected="true">Home</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="pills-profile-tab" data-bs-toggle="pill" data-bs-target="#pills-profile" type="button" role="tab" aria-controls="pills-profile" aria-selected="false">Profile</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="pills-contact-tab" data-bs-toggle="pill" data-bs-target="#pills-contact" type="button" role="tab" aria-controls="pills-contact" aria-selected="false">Contact</button>
  </li>
  <li class="nav-item" role="presentation">
    <button class="nav-link" id="pills-disabled-tab" data-bs-toggle="pill" data-bs-target="#pills-disabled" type="button" role="tab" aria-controls="pills-disabled" aria-selected="false" disabled>Disabled</button>
  </li>
</ul>
<div class="tab-content" id="pills-tabContent">
  <div class="tab-pane fade show active" id="pills-home" role="tabpanel" aria-labelledby="pills-home-tab" tabindex="0">...</div>
  <div class="tab-pane fade" id="pills-profile" role="tabpanel" aria-labelledby="pills-profile-tab" tabindex="0">...</div>
  <div class="tab-pane fade" id="pills-contact" role="tabpanel" aria-labelledby="pills-contact-tab" tabindex="0">...</div>
  <div class="tab-pane fade" id="pills-disabled" role="tabpanel" aria-labelledby="pills-disabled-tab" tabindex="0">...</div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>


Solution

  • You could do it like this. The notes are below the example.

    The example itself was posted like this (instead of breaking it into appropriate parts in the snippet editor) because there were issues in getting it to work as it does now. I suspect it has something to do with the way the external files are loaded on SO.

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>Hello, world!</title>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width,initial-scale=1" />
            <meta name="description" content="" />
            <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
            <style>
                .tab-content {
                    position: relative;
                }
                .tab-content > .tab-pane {
                    display: unset;
                    position: absolute;
                    left: 0;
                    opacity: 0;
                    transition: opacity 2s;
                }
                .tab-content > .tab-pane.active {
                    opacity: 1;
                }
                .tab-pane > div {
                    width: 200px;
                    height: 200px;
                    margin: 15px;
                }
                .red {
                    background-color: red;
                }
                .blue {
                    background-color: blue;
                }
                .yellow {
                    background-color: yellow;
                }
                .purple {
                    background-color: purple;
                }
            </style>
        </head>
        <body>
            <div class="container">
                <ul class="nav nav-pills mb-3" id="pills-tab" role="tablist">
                  <li class="nav-item" role="presentation">
                    <button class="nav-link active" id="pills-home-tab" data-bs-toggle="pill" data-bs-target="" type="button" role="tab" aria-controls="pills-home" aria-selected="true">Home</button>
                  </li>
                  <li class="nav-item" role="presentation">
                    <button class="nav-link" id="pills-profile-tab" data-bs-toggle="pill" data-bs-target="" type="button" role="tab" aria-controls="pills-profile" aria-selected="false">Profile</button>
                  </li>
                  <li class="nav-item" role="presentation">
                    <button class="nav-link" id="pills-contact-tab" data-bs-toggle="pill" data-bs-target="" type="button" role="tab" aria-controls="pills-contact" aria-selected="false">Contact</button>
                  </li>
                  <li class="nav-item" role="presentation">
                    <button class="nav-link" id="pills-disabled-tab" data-bs-toggle="pill" data-bs-target="" type="button" role="tab" aria-controls="pills-disabled" aria-selected="false" disabled>Disabled</button>
                  </li>
                </ul>
                <div class="tab-content" id="pills-tabContent">
                  <div class="tab-pane fade show active" id="pills-home" role="tabpanel" aria-labelledby="pills-home-tab" tabindex="0">
                    <div class="red">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer ...</div>
                  </div>
                  <div class="tab-pane fade" id="pills-profile" role="tabpanel" aria-labelledby="pills-profile-tab" tabindex="0">
                    <div class="blue">... took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining ...</div>
                  </div>
                  <div class="tab-pane fade" id="pills-contact" role="tabpanel" aria-labelledby="pills-contact-tab" tabindex="0">
                    <div class="yellow">... essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing...</div>
                  </div>
                  <div class="tab-pane fade" id="pills-disabled" role="tabpanel" aria-labelledby="pills-disabled-tab" tabindex="0">
                    <div class="purple">Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old.</div>
                  </div>
                </div>
            </div>
            <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
            <script>
                const pills = document.querySelectorAll("button.nav-link");
                const tabs = document.querySelectorAll(".tab-pane");
    
                for(var i = 0; i < pills.length; i++) {
                    pills[i].addEventListener("click", function(event) {
                        let contentId = event.target.getAttribute("id").replaceAll("-tab","");
                        let elemTab = document.getElementById(contentId);
    
                        for(var j = 0; j < tabs.length; j++) {
                            tabs[j].classList.remove("active");
                        }
    
                        if(elemTab) {
                            elemTab.classList.add("active");
                        }
                    });
                }
            </script>
        </body>
    </html>

    Some caveats / YMMV / general notes:

    .tab-content {
        position: relative;
    }
    .tab-content > .tab-pane {
        display: unset;
        position: absolute;
        left: 0;
        opacity: 0;
        transition: opacity 2s;
    }
    .tab-content > .tab-pane.active {
        opacity: 1;
    }