Search code examples
javascripthtmlcssformsheight

How can I prevent scrolling to top of page when changing the height of a div within a form?


I have a form with checkbox inputs that follow a certain hierarchy. I'm trying to make it so that clicking a button next to the input of a category toggles between showing and hiding the inputs of its subcategories. The toggling itself works just fine but it triggers a scroll to the top of the page. When I comment out the form tags the toggle works perfectly without the scrolling.

For reference, here's my html

function showSubcategories(show_button) {
    let category_div = show_button.parentNode;
    let subcategories_divs = category_div.querySelectorAll('.subcategory');
    for (var i=0; i<subcategories_divs.length; i++) {
        subcategories_divs[i].style.height = "32px";
    }
    show_button.style.display = "none";
    category_div.querySelector('.hide-button').style.display = "inline-block";
}

function hideSubcategories(hide_button) {
    let category_div = hide_button.parentNode;
    let subcategories_divs = category_div.querySelectorAll('.subcategory');
    for (var i=0; i<subcategories_divs.length; i++) {
        subcategories_divs[i].style.height = "0px";
    }
    hide_button.style.display = "none";
    category_div.querySelector('.show-button').style.display = "inline-block";
}
.subcategory {
    padding-left: 20px;
    overflow: hidden;
    height: 0;
    transition: 1s;
}
<form>
    <div>
        <input type="checkbox" value="category">
        <label for="category">category</label>
        <button class="show-button" onclick="showSubcategories(this)">&#8744</button>
        <button class="hide-button" onclick="hideSubcategories(this)">&#8743</button>
        <div class="subcategory">
            <input type="checkbox" value="subcategory1">
            <label for="subcategory1">subcategory1</label>    
        </div>
        <div class="subcategory">
            <input type="checkbox" value="subcategory2">
            <label for="subcategory2">subcategory2</label>    
        </div>
    </div>
</form>

I'm altering the height of each individual subcategory input separately because there's a variable number of subcategories for each category. I've tried placing all the subcategories within a single div and changing that div's height but I get the same issue. Any thoughts?


Solution

  • The default type of a button is submit:

    type = submit|button|reset [CI]

    This attribute declares the type of the button. Possible values:

    submit: Creates a submit button. This is the default value.

    https://www.w3.org/TR/html401/interact/forms.html#h-17.5

    So you'd have to use event.preventDefault() to cancel the submit, or specify type="button" for the buttons.

    function showSubcategories(show_button) {
        show_button.parentNode.classList.toggle("open", true);
    }
    
    function hideSubcategories(hide_button) {
        hide_button.parentNode.classList.toggle("open", false);
    }
    .subcategory {
        padding-left: 20px;
        overflow: hidden;
        height: 0;
        transition: 1s;
    }
    div.menu:not(.open) > .hide-button,
    div.menu.open > .show-button
    {
      display: none;
    }
    div.menu.open > .subcategory
    {
      height: 32px;
    }
    <form>
        <div class="menu">
            <input type="checkbox" value="category">
            <label for="category">category</label>
            <button class="show-button" type="button" onclick="showSubcategories(this)">&#8744</button>
            <button class="hide-button" type="button" onclick="hideSubcategories(this)">&#8743</button>
            <div class="subcategory">
                <input type="checkbox" value="subcategory1">
                <label for="subcategory1">subcategory1</label>    
            </div>
            <div class="subcategory">
                <input type="checkbox" value="subcategory2">
                <label for="subcategory2">subcategory2</label>    
            </div>
        </div>
    </form>