Search code examples
csscss-animationscss-transforms

Adjacent CSS Collapsible Widgets


I used this tutorial (https://alligator.io/css/collapsible/) to create 2 collapsible widgets. I need the header labels to be adjacent to each other on the same line with the collapsible part takeing up the length of both headers like whats shown in the image. How can this be done?

I've tried using position: absolute; but then one header remains unselectable and the containing border it's surrounded by remains unaffected by its expansion which is a problem.

enter image description here

Also, how would I make it so that if one collapsible widget is open the other is automatically closed?


Solution

  • You need to change several things:

    1. Change your HTML structure.
    2. Check the first radio by default to show the first tab content by default.
    3. In the wrapper element, change display: grid by display: flex and wrap the content
    4. I made a lot of necessary modifications to the CSS so check that out.

    body {
      font-family: consolas;
    }
    
    *,
    *::before,
    *::after {
      box-sizing: border-box;
    }
    
    input.collapse[type="radio"] {
      display: none;
    }
    
    .lbl-toggle {
      cursor: pointer;
      border: solid 1px #FAE042;
      transition: all 0.25s ease-out;
      order: 1;
      display: block;
      padding: .3rem 1rem;
      width: 50%;
      background-color: rgba(250, 224, 66, .2);
      font-weight: bold;
    }
    
    .lbl-toggle:hover {
      color: #000;
    }
    
    .lbl-toggle:first-of-type {
      border-top-left-radius: 7px;
    }
    
    .lbl-toggle:last-of-type {
      border-top-right-radius: 7px;
    }
    
    .collapsible-content {
      overflow: hidden;
      width: 100%;
      max-height: 0;
      order: 2;
      padding: 0 1rem;
      background-color: #FAE042;
      border-bottom: 1px solid rgba(250, 224, 66, .45);
      border-bottom-left-radius: 7px;
      border-bottom-right-radius: 7px;
      display: inline-block;
    }
    
    .toggle:checked+.lbl-toggle {
      background-color: #FAE042;
    }
    
    .toggle:checked+.lbl-toggle+.collapsible-content {
      max-height: 100%;
    }
    
    .collapsible-content th.head {
      padding: 6px 4px;
      font-size: small;
    }
    
    .collapsible-content td.data {
      padding: 6px 4px;
    }
    
    .lbl-toggle::after {
      content: " ";
      display: inline-block;
      border-top: 5px solid transparent;
      border-bottom: 5px solid transparent;
      border-left: 5px solid currentColor;
      vertical-align: middle;
      margin-left: 0.7rem;
      transition: transform 0.2s ease-out;
    }
    
    .toggle:checked+.lbl-toggle::after {
      transform: rotate(90deg);
    }
    
    .toggle:checked+.lbl-toggle {
      border-bottom-right-radius: 0;
      border-bottom-left-radius: 0;
    }
    
    .wrapper {
      display: flex;
      flex-wrap: wrap;
    }
    <div class="wrapper">
      <input class="collapse toggle" id="#collapsible1" type="radio" name="collapsibleItem" checked/>
      <label for="#collapsible1" class="lbl-toggle">
            Header 1        
            </label>
      <div class="collapsible-content">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum, sapien et consectetur finibus, elit ex sodales purus, vel pretium libero lectus feugiat erat.</p>
      </div>
    
    
      <input class="collapse toggle" id="#collapsible2" type="radio" name="collapsibleItem" />
      <label for="#collapsible2" class="lbl-toggle">
              Header 2          
            </label>
      <div class="collapsible-content">
        <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum, sapien et consectetur finibus, elit ex sodales purus, vel pretium libero lectus feugiat erat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed fermentum, sapien et
          consectetur finibus, elit ex sodales purus, vel pretium libero lectus feugiat erat. </p>
      </div>
    </div>

    For the second question, you can use radio buttons instead of checkboxes.

    <input id="collapsible1" name="collapsibleItem" class="toggle" type="radio">
    <input id="collapsible2" name="collapsibleItem" class="toggle" type="radio">
    <input id="collapsible3" name="collapsibleItem" class="toggle" type="radio">
    
    input[type='radio'] {
      display: none;
    }
    

    Notice that all radios have the same name attribute; that's necessary to unmark the current marked radio when you check a new one.