Building CSS Only interactive components from scratch - Part II (accordion/collapsible)

JoelBonetR 🥇 - Jun 2 '20 - - Dev Community

*Each post about Building CSS Only interactive components is stand alone, so you don't need to understand part 1 to understand the part 2. Feel free to check it in the order you want, need or like.
Also a basic understanding about how CSS works is required to understand the workarounds of this posts. If you want to level up your CSS acknowledgement, you can visit this post .


  1. Building CSS Only interactive components from scratch PART 1
  2. Building CSS Only interactive components from scratch PART 2
  3. Building CSS Only interactive components from scratch PART 3

Hi everybody! Today I'm gonna show you how to achieve a collapsible element / accordion using :checked CSS pseudo-selector.

Instead using JavaScript for moving or showing/hiding content, we'll use CSS to do the trick.

Let's put our hands on

Structure:

  <section class="accordion">
    <div class="accordion-element">
      <input type="checkbox" id="check-2" />
      <label for="check-2">Accordion second item 
        <span class="accordion-indicator"> </span>
      </label>
      <article>
        <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Ullam dolorem alias numquam? Ipsa voluptate eligendi quasi beatae alias adipisci suscipit id qui temporibus repellendus placeat aperiam magnam sunt, voluptatum explicabo?
        </p>
      </article>
    </div>
    <div class="accordion-element">
      <input type="checkbox" id="check-3" />
      <label for="check-3">Accordion third item 
        <span class="accordion-indicator"> </span>
      </label>
      <article>
        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Autem magni quos odio modi sed earum corporis, fugit aspernatur, suscipit voluptatum eaque id omnis sequi nobis esse aliquam quaerat magnam cumque. 
        </p>
      </article>
    </div>
  </section>

Styling (SCSS) explained with comments:


.accordion {
  /*
    hide default input
  */
  input {
    display: none;
  }
  /*
    Set label properties for UX like cursor:pointer and styling as we like.
  */
  label {
    font-size: 20px;
    font-weight: 600;
    background: #fefefe;
    border-radius: .25em;
    cursor: pointer;
    display: block;
    margin-bottom: .125em;
    padding: .5em;
    z-index: 20;

    /*
      Add styling and transition for the indicator to give feedback
    */
    span.accordion-indicator {
      transition: all 0.4s;
      width: 13px;
      height: 13px;
      margin-top: 5px;
      margin-right: 5px;
      display: inline-block;
      border: solid #282828;
      border-width: 0 2.5px 2.5px 0;
      -webkit-transform: rotate(45deg);
      -ms-transform: rotate(45deg);
      transform: rotate(45deg);
      float: right;
    }
  }
  .accordion-element {
    margin-bottom: 5px;
  }
  label:hover, .accordion-element:hover {
    background: #f5f5f5;
  }
  
  /* 
    When the input is checked (as you click on the label which has a 
    for attribute pointing yo input id), rotate the indicator, set a 
    background to the label and show the content inside the article 
  */
  input:checked + label {
    background: #f0f0f0;
    border-bottom-right-radius: 0;
    border-bottom-left-radius: 0;
    color: #282828;
    margin-bottom: 0;
    span.accordion-indicator { 
      -webkit-transform: rotate(225deg);
      -ms-transform: rotate(225deg);
      transform: rotate(225deg);
      margin-top: 10px;
    }
  }
  /*
    Set default properties to the article (accordion content)
  */
  article {
    background: #fefefe;
    border-bottom-left-radius: .25em;
    border-bottom-right-radius: .25em;
    border-bottom: 2px solid #f0f0f0;
    border-left: 2px solid #f0f0f0;
    border-right: 2px solid #f0f0f0;
    overflow: hidden;
    z-index: 10;
    transition: max-height .25s;
  }
  input:not(:checked) ~ article {
    max-height: 0;
  }
  /*
    Set max-height to the article, you may need to increase this 
    max-height to the maximum you need for your content. It's 
    better to stablish it the lowest possible as there's an 
    animation pointing this property and the lowest value give the 
    best performance.
  */
  input:checked ~ article {
    height: auto;
    max-height: 500px;
    margin-bottom: .125em;
  }
  article p {
    padding: 1em;
  }
}

Result:

If you want or need to show the first one expanded by default, all you need is to add the checked attribute to the given input (no value needed, but if you are in preact or something similar that uses XML, you can set checked="checked" or checked="true".

Example:

 <input type="checkbox" id="check-1" checked />

As you can see, you can use as many collapsible elements as you want to form an accordion, or use a single one if you need isolated collapsible elements (collapsed or not by default), so I think it's useful to add on your projects when needed.

If you want to see this feature inside a real project, check my Building an efficient portfolio from scratch article.

Next post I'll add a tab panel with tabs using same methodology.

Hope you find this article useful and see you in next post!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .