Implement an expand/collapse effect using CSS3 transitions

How can I implement a smooth expand/collapse effect?

function expandCollapse(shID) {
    if (document.getElementById(shID)) {
        if (document.getElementById(shID + '-show').style.display != 'none') {
            document.getElementById(shID + '-show').style.display = 'none';
            document.getElementById(shID).style.display = 'block';
        } else {
            document.getElementById(shID + '-show').style.display = 'inline';
            document.getElementById(shID).style.display = 'none';
        }
    }
}
.more {
    display: none;
    padding-top: 10px;
}

a.showLink,
a.hideLink {
    text-decoration: none;
    -webkit-transition: 0.5s ease-out;
    background: transparent url('down.gif') no-repeat left;
}

a.hideLink {
    background: transparent url('up.gif') no-repeat left;
}
Here is some text.
<div class="readmore">
    <a href="#" id="example-show" class="showLink" onclick="expandCollapse('example');return false;">Read more</a>
    <div id="example" class="more">
        <div class="text">Here is some more text: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vitae urna nulla. Vivamus a purus mi. In hac habitasse platea dictumst. In ac tempor quam. Vestibulum eleifend vehicula ligula, et cursus nisl gravida sit amet. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</div>
        <p><a href="#" id="example-hide" class="hideLink" onclick="expandCollapse('example');return false;">Hide</a></p>
    </div>
</div>

http://jsfiddle.net/Bq6eK/1

Answer №1

Here is the solution I came up with to automatically adjust the height:

function resizeDiv() {
  var resizeDiv = document.getElementById('resize');
  if (resizeDiv.clientHeight) {
    resizeDiv.style.height = 0;
  } else {
    var wrapper = document.querySelector('.measuringWrapper');
    resizeDiv.style.height = wrapper.clientHeight + "px";
  }
  document.getElementById("expand-button").value = document.getElementById("expand-button").value == 'Show more' ? 'Show less' : 'Show more';
}
#expand-button {
  border-style: none;
  background: none;
  font: 16px Arial;
  color: green;
  margin: 0 0 10px 0;
}

#resize input:checked {
  color: orange;
}

#expand-button:hover {
  color: purple;
}

#resize {
  -moz-transition: height .5s;
  -ms-transition: height .5s;
  -o-transition: height .5s;
  -webkit-transition: height .5s;
  transition: height .5s;
  height: 0;
  overflow: hidden;
}
<input type="button" onclick="resizeDiv()" value="Show more" id="expand-button">

<div id='resize'>
  <div class='measuringWrapper'>
    <div class="text">I added some extra text: Ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vitae urna nulla. Vivamus a purus mi. In hac habitasse platea dictumst. In ac tempor quam. Vestibulum eleifend vehicula ligula, et cursus nisl gravida sit
      amet. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.</div>
  </div>
</div>

I implemented a workaround inspired by the method shared by r3bel: Is it possible to use CSS3 for transitioning between height:0 and the dynamic height of content?

Answer №2

Click here for a solution that should do the trick. I had to experiment a bit too! :D

function showHide(shID) {
  if (document.getElementById(shID)) {
    if (document.getElementById(shID + '-show').style.display != 'none') {
      document.getElementById(shID + '-show').style.display = 'none';
      document.getElementById(shID + '-hide').style.display = 'inline';
      document.getElementById(shID).style.height = '100px';
    } else {
      document.getElementById(shID + '-show').style.display = 'inline';
      document.getElementById(shID + '-hide').style.display = 'none';
      document.getElementById(shID).style.height = '0px';
    }
  }
}
#example {
  background: red;
  height: 0px;
  overflow: hidden;
  transition: height 2s;
  -moz-transition: height 2s;
  /* Firefox 4 */
  -webkit-transition: height 2s;
  /* Safari and Chrome */
  -o-transition: height 2s;
  /* Opera */
}

a.showLink,
a.hideLink {
  text-decoration: none;
  background: transparent url('down.gif') no-repeat left;
}

a.hideLink {
  background: transparent url('up.gif') no-repeat left;
}
Here is some text.
<div class="readmore">
  <a href="#" id="example-show" class="showLink" onclick="showHide('example');return false;">Read more</a>
  <div id="example" class="more">
    <div class="text">
      Here is some more text: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vitae urna nulla. Vivamus a purus mi. In hac habitasse platea dictumst. In ac tempor quam. Vestibulum eleifend vehicula ligula, et cursus nisl gravida sit amet.
      Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
    </div>
    <p>
      <a href="#" id="example-hide" class="hideLink" onclick="showHide('example');return false;">Hide</a>
    </p>
  </div>
</div>

Answer №3

Success achieved through the use of this animation technique.

const toggleButton = document.getElementById('toggleButton');
const wrapper = document.querySelector('.wrapper');

toggleButton.addEventListener('click', () => {
  wrapper.classList.toggle('open');
});
.expandable {
  min-height: 0;
  background: gray;
  color: white;
}

/* Initially, set the grid rows to take up no space (height 0).
   This effectively hides the content inside the wrapper element. */
.wrapper {
  display: grid;
  overflow: hidden;
  transition: grid-template-rows 400ms;
  grid-template-rows: 0fr;  /* 0fr means 0 fraction of available space */
}

/* When the 'open' class is applied to the wrapper element, set the grid rows to take up all available space (height 1fr).
   This expands the wrapper and shows the content inside. */
.wrapper.open {
  grid-template-rows: 1fr;  /* 1fr means 1 fraction of available space */
}
<button id="toggleButton">
  Toggle
</button>

<div class="wrapper">
  <div class="expandable">
    Here is some more text: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum vitae urna nulla. Vivamus a purus mi. In hac habitasse platea dictumst. In ac tempor quam. Vestibulum eleifend vehicula ligula, et cursus nisl gravida sit amet.
    Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
  </div>
</div>

Answer №4

After spending hours searching for a simple solution, I realized that the code I needed was not readily available. Determined to create something easy to use without relying on JQuery, I worked on some example code. Through trial and error, I discovered that setting the height and width is crucial for the animation to function properly.

<script>
        function dostuff() {
            if (document.getElementById('MyBox').style.height == "0px") {

                document.getElementById('MyBox').setAttribute("style", "background-color: #45CEE0; height: 200px; width: 200px; transition: all 2s ease;"); 
            }
            else {
                document.getElementById('MyBox').setAttribute("style", "background-color: #45CEE0; height: 0px; width: 0px; transition: all 2s ease;"); 
             }
        }
    </script>
    <div id="MyBox" style="height: 0px; width: 0px;">
    </div>

    <input type="button" id="buttontest" onclick="dostuff()" value="Click Me">

Answer №5

http://jsfiddle.net/Bq6eK/215/

Instead of adjusting your code, I came up with my own solution. It may not be exactly what you were looking for, but perhaps you can use it as a starting point. I made sure to add comments to explain the changes I made.

To address the issue of not setting the height in JavaScript, I included 'maxHeight' as a parameter in the toggleHeight JS function. This way, it can be defined in the HTML for each expandable div.

I'll be honest, I'm not an expert in front-end languages, and there's a small glitch where the 'Show/hide' button needs to be clicked twice initially for the animation to begin. It could be a focus-related problem.

Another flaw in my solution is that the hidden text can be revealed by selecting and dragging within the div. You can copy and paste the hidden text to a visible area without clicking the show/hide button.

To improve upon my solution, you could try making the show/hide button change dynamically. Based on your current knowledge of JS for displaying and hiding text, you might be able to implement this feature easily.

Answer №6

If you're looking for a JS-free solution, consider using checkboxes instead. Check out this example.

To hide the checkbox, simply apply this CSS:

.container input{
    display: none;
}

You can then style it to resemble a button.

For the original source code that I customized, visit this link.

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

"Chrome's failure to fire the appCache event for HTML5 has left developers scratching

Currently, I am working on an offline website using HTML5. In my JavaScript file, I have written some code for event listeners; however, the events are not being fired. var appCache = window.applicationCache; if (appCache) { appCache.addEventListener ...

Eliminating duplicate data submissions with jQuery Ajax

Encountering an issue with my jQuery AJAX submission process. JavaScript: $('#myform').submit(function () { if (validateEvenInputs()) { $('#btnevent').attr('disabled', 'disabled'); function ...

What are the strategies for distinguishing between languages in React Native prior to mounting the component?

I had high hopes for this solution, but unfortunately it doesn't work as expected. The issue is that this.text.pupil is undefined. Could the problem possibly be related to componentWillMount? If so, how can I handle multiple languages outside of ...

Learn how to extract JSON information from a URL and integrate it into either a table or dropdown in Vue.js

Looking to retrieve a JSON data array from a URL and utilize it to populate either a table or dropdown with Vue.js and Axios. Here is the link where I intend to fetch the data. Any advice on how to accomplish this? https://jsonplaceholder.typicode.com/us ...

Once the image is requested in HTML, three.js makes a subsequent request for the same image

This is a block of code. let image = new THREE.TextureLoader().load("http://odf9m3avc.bkt.clouddn.com/1493817789932.jpg") <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/88/three.min.js"></script> <img class='preLoad&apo ...

Choosing a particular 2D array based on another variable in jQuery and JavaScript

Within my project, I am utilizing 2D arrays to append specific divs under particular circumstances. In an effort to streamline and enhance the code, I attempted to create a variable that would determine which array to utilize based on the id of an HTML < ...

Trigger an event, pause, and subsequently trigger another one within Vue

I have successfully emitted the following events to the parent component: this.$emit('sendToParent1', true); this.$emit('sendToParent2'); this.$emit('sendToParent3'); this.$emit('sendToParent4', true); this.$emit(&ap ...

Exploring the search feature within Redux and React-Native

The search functionality in redux is giving me some trouble. I have written the following code for it, but strangely enough, it's not working properly. Interestingly, the same code works perfectly when used without redux. searchItems: (name ) => ...

What is the best way to manage a 301 redirect from a current page to a new page within my index.js script?

Hello everyone, hope you're having a great Friday! I'm looking for advice on the best approach to handle a 301 redirect in node.js from an existing file to another file. Let's say I currently have a file called /contact router.get('/con ...

Arranging the elements in my footer for optimal display

My footer layout expands and the lists in each column become misaligned as I add more links to it. I want to make sure that the lists for each column are aligned horizontally on the same row, with the title of each column also in the same row. levi | ...

CSS - Combining Selectors and Pseudo Classes to Boost Styling

When it comes to grouping selectors in CSS, there is an easy way to do it like this: .class1 #id1, .class2 #id2, .class3 #id3 { } Applying pseudo classes on these grouped selectors can be a bit repetitive. Is there a method to group multiple selectors a ...

Tips for fading out two elements after completing a drag and drop action

Visit this Codepen for more examples - Codepen I have been developing a drag and drop feature in my application. Once the item is dropped, it transitions from red to green and fades out smoothly. The droppable element behind the draggable should also fad ...

The Redux Toolkit Slice Reducer fails to function properly when incorporating an extra Reducer that is not compatible

I am relatively new to the world of Redux and have been attempting to use RTK right from the start. It has been quite a challenging and confusing experience for me so far. Recently, I decided to include a standard Reducer instead of an extraReducer in my ...

Passing Data from $http.get to Angular Controller Using a Shared Variable

One issue I'm facing is the inability to pass the content of a variable inside $http.get() to the outside scope, as it always returns undefined. I attempted using $rootScope, but that approach was not successful. controller('myControl', fu ...

Choose Your Preferences When the Page Loads

I have a dropdown menu where I can select multiple options at once without checkboxes. When the page loads, I want all of the options to be pre-selected by default. I am aware that I can use $(document).ready() to trigger actions after the page has load ...

The challenge of navigating CSS specificity guidelines

In my CSS file, I have defined two styles for a table with the class "myTable". The first style sets the background color of header cells to gray, while the second style sets the background color of odd rows to blue: .myTable th { background-color: gr ...

What is the process for sending an image as input to a Django view using an Angular frontend?

I currently have a django web api with an angular frontend that allows users to upload and view images. My goal now is to expand this functionality: when the user clicks the "segment" button (see image), it should send the corresponding image to my python ...

Initiate a click event on an anchor element with the reference of "a href"

I'm currently facing an issue with clicking a href element on my HTML website. The click event doesn't seem to be triggered. CODE: HTML CODE: <div class="button" id="info" ></div> <ul id="game-options"> <li><a ...

Access Sharepoint from an external site

Looking for assistance with a SharePoint list containing columns for Name, Position, Office, and Salary. Upon logging in with specific credentials to the SharePoint website, I need to retrieve all items from the list and showcase them on my own website. ...

"Exploring the functionality of HTML buttons on iOS Safari with Angular click

Currently, I am developing a web app that includes a feature where users can hold down a button to adjust a value. The backend of the app is supported by Meteor.js with Angular serving as the front end. The functionality works perfectly, except for Mobile ...