Navigate to the top of a Bootstrap accordion when it is expanded

Recently, I've been working on a small blog and I want to make consecutive blog posts accessible from within an accordion. This will allow users to easily skim through post titles, select the one they find interesting, read it, and seamlessly go back to skimming without having to navigate unnecessary menus.

However, I'm facing an issue where once a user finishes reading a post and clicks on a second one, the second post doesn't open at the top with the title visible. Instead, it opens 2/3 of the way down due to scrolling while reading the first post. This forces the user to manually scroll back up to the top of the post they haven't read yet. I've tried various solutions but nothing seems to work. Any help would be greatly appreciated!

UPDATE: I discovered that the slim version of jQuery I was using didn't have the functions I needed. Now that I've resolved that issue, everything compiles fine but I still can't figure out how to scroll the page to the right position.

The closest solution I found is this code snippet, which scrolls back up to the first card-header when a new section is opened. However, I want it to scroll to the specific card-header that was clicked.

$(".card-header").click(function (event) {                                      
    $('html, body').animate({                                                   
        scrollTop: $(".card-header").offset().top                               
    }, 300);                                                                    
}); 

I'm attempting to achieve something similar to this logical equivalent piece of code, which unfortunately doesn't scroll at all despite compiling correctly. Even replacing $(this) with $(event.target) or $(event.target).parent() has not yielded any results.

$(".card-header").click(function(event) {                                                                           
    $('html, body').animate({                                                   
        scrollTop: $(this).offset().top-60                     
    }, 300);  

Here's a minimal working example to demonstrate my challenges:

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>


<div class="container" id="container">
  
  <div class="card">                                          
    <a class="card-header" data-toggle="collapse" href="#sec1">Title1</a>
    <div id="sec1" class="collapse" data-parent="#container">  
      <div class="card-body">                             
        lots and lots of text
      </div>                                              
    </div>                                                  
  </div>
  
  <div class="card">                                          
    <a class="card-header" data-toggle="collapse" href="#sec2">Title2</a>
    <div id="sec2" class="collapse" data-parent="#container">  
      <div class="card-body">                             
        lots and lots of text
      </div>                                              
    </div>                                                  
  </div>
  
</div>

Answer №1

Make sure to always scroll to the offset-top of the opening collapse element. If the closing collapse is positioned above the opening one, then deduct the height of the closing collapse from the offset-top of the opening collapse.

jQuery(function($){
  $('.card-header').each(function(){
    let $card_header = $(this);
    let $collapse_element = $card_header.next();
    $collapse_element.on('show.bs.collapse', function () {
      let $card_header_top = $card_header.offset().top;
      let $visible_collapse = $('.collapse.show');
      if($visible_collapse.length){
        let $visible_collapse_top = $visible_collapse.offset().top;
        if($visible_collapse_top < $card_header_top){
          $card_header_top -= $visible_collapse.height();
        }
      }
      $([document.documentElement, document.body]).animate({
        scrollTop: $card_header_top
      });
    });
  });
});
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>

<div style="height:30px"></div>
<div class="container" id="container">
  <div class="card">                                          
    <a class="card-header" data-toggle="collapse" href="#sec1">Title1</a>
    <div id="sec1" class="collapse" data-parent="#container">  
      <div class="card-body">                             
        lots and lots of text
        ...
      </div>                                            
    </div>                                                
  </div>
  
  <div class="card">                                          
    <a class="card-header" data-toggle="collapse" href="#sec2">Title2</a>
    <div id="sec2" class="collapse" data-parent="#container">  
      <div class="card-body">                              
        lots and lots of text
        ...
      </div>                                             
    </div>                                                 
  </div>
  
</div>

Answer №2

I made a simple tweak by adding an id to the <div class="card"> tag, changing it to

<div class="card" id="div2">
, and included some JavaScript:

$(".card-header").click(function () {
  $('html, body').animate({
    scrollTop: $("#div2").offset().top
  }, 2000);
});

This solution worked perfectly for me without the need to overwrite everything.

Answer №3

Enjoy at gathering

 $(document).ready(function () {
     $("html, body").animate({
            scrollTop: 0  
     }, 600);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

Have a blast!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Enhance the clarity of content within an IFrame by sharpening the focus on

I recently developed an iframe to open a chat site I built using React.js and Tailwind. The iframe is loaded dynamically on the website through javascript. However, I noticed that when I click on the input field inside the iframe, the content appears blurr ...

Tips for monitoring multiple values in a Vue 3 script setup

Within my code, I currently have a watcher set up like this (inside <script setup>): const form = reactive({ body: '', image: '' }) watch(() => form.image, () => { console.log(form.image) }) I am looking to enh ...

Changing all object values to true with React useState

In a certain file, I have defined an object with the following structure: export const items = { first: false, second: false, third: false } Within a component, I am using this object as shown below: import { items } from 'file'; const [el ...

How can I pass command line variables into an npm script?

I am facing an issue where I am attempting to pass a command line option (which is not stored in version control) to my main script index.js. This script performs specific actions based on a designated S3 bucket. Here is the relevant section from my packa ...

How to bypass validation for required input in jQuery validate plugin

As an example, consider the <input name="surname" id="surname" type="text">. Sometimes I want to hide this input and make it non-required. My current workaround is to set a value such as "some value" when hiding the input, and then remove this value ...

Issue: Configuration Error - CKEditor5 cannot be loaded for extension in Vuejs

Hey everyone, I'm currently facing an issue. I'm trying to customize a build and everything works fine in the cloned ckeditor along with the sample.html file. However, when attempting to implement the customized build in Vue 2, I encounter an err ...

Activate the radio button with jQuery when the event occurs

I have been experimenting with using HTML and JS along with the functionality provided by bootstrap-switch.org to toggle between two groups of radio buttons within a form. However, I am encountering difficulty in setting the first radio button in the secon ...

JavaScript: Exploring Content Inside Headers

Using document.body.innerHTML allows you to search within the body of a webpage. Is there an equivalent method for searching within the "Head" section? I've been looking around but so far, I haven't come across any such function. ...

Struggling with getting content to evenly distribute using Justify-content-around

I've been attempting to evenly distribute some spans according to the instructions provided in this bootstrap documentation, but unfortunately, the spans are not spreading out as expected. I'm using justify-content-around just like the documentat ...

The issue of Datatables child row not refreshing when using AJAX

I'm attempting to retrieve child row data in Datatables using AJAX: $('#myTable tbody').on('click', 'td', function () { var tr = $(this).closest('tr'); var row = myTable.row( tr ); if ( row.child.isS ...

Changing a date format in typescript: Here is how you can easily convert a date from one

Using React with Typescript: I am currently working with a date picker from material-ui version 5. The date picker requires the date value to be in the format "yyyy-MM-dd". However, the API returns a Date object in the format "2022-01-12T00:00:00.000+00:0 ...

The jQuery ajax() function may return a null value

I'm attempting to create a simple query: $.ajax({ url: "ajaxfunc.php", dataType: 'json', success: function(data){ alert(data.resp); } }); In my ajaxfunc.php file, the code looks like this: <?php echo ...

Convert a boolean value to a string using filter in AngularJS

I am working on an AngularJS app and need to create a filter. In my database, I have a string value that indicates whether the data is active or inactive. I use 'S' for active and 'N' for inactive. I added a checkbox button on my page t ...

Adjust the background color of the choices in the select box

I'm looking to customize the appearance of a drop-down menu in a form on a website by making the background of the options transparent, similar to the initial selection. I've tried using background:rgba(255, 255, 255, 0.2) for this purpose, but ...

Managing an Angular timer: Starting and resetting it via the controller

Is there a way to start a timer when the user clicks on the recordLogs method and reset the timer when the user clicks on the stopLogs method? According to the angular-timer documentation, we should be able to use the timer-stop and timer-clear methods to ...

Achieve a consistently displayed shopping cart icon on the right side of the menu with Bootstrap

I have attempted to ensure that the shopping cart icon always appears on the right side of the screen for mobile, tablet, and desktop users using Bootstrap. However, I am facing issues with responsiveness. How can I ensure that the shopping cart icon alway ...

Guidelines for accessing the value of the parent function upon clicking the button within the child function?

I have a pair of buttons labeled as ok and cancel. <div class="buttons-div"> <button class='cancel'>Cancel</button> <button class='ok'>Ok</button> </div> The functions I am working wi ...

The Issue of Anti Forgery Token Not Functioning Properly with Ajax JSON.stringify Post

I have been attempting to utilize an Anti Forgery token with JSON.stringify, but despite researching multiple sources, I have not been successful. Below is my AJAX code for deleting some information without any issues. Upon adding the anti forgery token, I ...

Utilizing Angular PrimeNG's range datepicker, you can select a date range spanning from January 31st to December 1st, 2023 within a reactive form. Take it a step further by calculating

Here is some HTML code: <div class="row"> <div class="col-4"> <p-calendar label="startDate" formControlName="startDate" [minDate]="daMaxRange" ...

The Javascript Date constructor struggles to interpret date strings in certain timezones that are not enclosed in brackets

Take a look at the examples below: new Date("Wed, 28 May 2014 09:50:06 EEST"); // Invalid Date new Date("Thu, 26 Jun 2014 09:09:27 EDT"); // OK, is parsed new Date("Wed, 28 May 2014 09:50:06 (EEST)"); // OK, is parsed new Date("Thu, 26 Jun 2014 09:09:27 ( ...