css Audio - Active file-generic CSS - Active Generic - Active HTML - Active JS - Active SVG - Active Text - Active file-generic Video - Active header Love html icon-new-collection icon-person icon-team numbered-list123 pop-out spinner split-screen star tv

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <div class="wrapper">
  <section class="details-group">
    <details class="details" open>
      <summary class="details__summary">
        &lt;details&gt; and &lt;summary&gt;
      </summary>
      <div class="details__content">
        <p>The &lt;details&gt; and &lt;summary&gt; elements are used to allow common accordion-style functionality without relying on JavaScript.</p>
      </div>
    </details>

    <details class="details">
      <summary class="details__summary">Making it better</summary>
      <div class="details__content">
        <p>With a little help from JavaScript, we can supplement the default behavior to make an accordion that is super smooth and nicely-styled, but still degrades gracefully.</p>
        <p>This accordion uses JS to calculate heights so we can use CSS transitions without any max-height hacks. It also sets a timeout before removing the <code>open</code> attribute, so the content of the <code>&lt;details&gt;</code> element will stay visible until the height transition is finished.</p>
        <p>The cool part is that since we&rsquo;re using these modern HTML5 elements, the accordion should work just fine even with JavaScript disabled. <strong><em>Gasp!</em> A simple web component in 2018 that doesn&rsquo;t completely fail without JS?! Sound the alarm!</strong>
      </div>
    </details>

    <details class="details">
      <summary class="details__summary">Settings</summary>
      <div class="details__content">
        <ul>
          <li>
            <strong><code>speed</code></strong> <em>(default: <code>300</code>)</em> Speed of the transition in milliseconds. Setting this in the plugin will override the value specified in the CSS.
          </li>
          <li>
            <strong><code>one_visible</code></strong> <em>(default: <code>false</code>)</em> Determines whether details can be toggled independently, or if only one can be visible at a time.
          </li>
        </ul>
      </div>
    </details>

    <details class="details">
      <summary class="details__summary">Shameless Plug</summary>
      <div class="details__content">
        <p>If you liked this pen, check out <a target="_blank" href="https://keithpickering.github.io">my portfolio site</a>. I&rsquo;m accepting new projects all the time, so drop me a line.</p>
      </div>
    </details>
  </section>
</div>
            
          
!
            
              @import url('https://fonts.googleapis.com/css?family=Oswald:300|Roboto:300,500');

$spacing: 24px;
$plus-size: 16px;
$plus-thickness: 2px;
$speed: 300ms;
$easing: ease-in-out;
$gray-dark: #546E7A;
$gray: #CFD8DC;
$gray-light: #ECEFF1;
$primary: #00ACC1;

html, body {
  min-height: 100%;
}

html {
  overflow-y: scroll;
  font-size: 18px;
}

body {
  font-size: 1rem;
  font-weight: 300;
  font-family: Roboto, sans-serif;
  line-height: 1.4;
  color: $gray-dark;
  background-color: $gray-light;
}

p, ul, li {
  margin: 0;
  padding: 0;
  margin-bottom: $spacing;
  
  &:last-child {
    margin-bottom: 0;
  }
}

a { color: $primary; }

code { background: $gray-light; }

.wrapper {
  max-width: 640px;
  margin-left: auto;
  margin-right: auto;
  padding: $spacing*2;
}

.details-group {
  border: 1px solid $gray;
  border-radius: 5px;
  background-color: white;
}

.details {
  overflow: hidden;
  border-bottom: 1px solid $gray;
  transition: height $speed $easing;
  
  &:last-child {
    border-bottom: 0;
  }
  
  &__summary,
  &__content {
    padding: $spacing;
  }
  
  &__summary {
    position: relative;
    list-style: none; // Hide the marker (proper method)
    padding-left: $spacing*2;
    outline: 0;
    cursor: pointer;
    font-size: 1.4rem;
    font-family: Oswald;
    text-transform: uppercase;
    transition: color $speed $easing;
    
    [open] > & {
      color: $primary;
    }
    
    // Hide the marker in Webkit
    &::-webkit-details-marker {
      display: none;
    }
    
    // Our replacement marker
    &:before,
    &:after {
      content: "";
      position: absolute;
    }
    
    &:before {
      left: $spacing/2 + $plus-size/2;
      top: 50%;
      height: $plus-thickness;
      margin-top: -$plus-thickness/2;
      width: $plus-size;
      background: $primary;
    }
    
    &:after {
      left: $spacing/2 + $plus-size;
      top: 50%;
      height: $plus-size;
      margin-top: -$plus-size/2;
      width: $plus-thickness;
      margin-left: -$plus-thickness/2;
      background: $primary;
      transition: all $speed $easing;
    }
    
    [open] &:after {
      opacity: 0;
      transform: translateY(25%);
    }
  }
  
  &__content {
    padding-top: 0;
    padding-left: $spacing*2; 
  }
}
            
          
!
            
              class Details {
  constructor(el, settings) {
    this.group    = el;
    this.details  = this.group.getElementsByClassName("details");
    this.toggles  = this.group.getElementsByClassName("details__summary");
    this.contents = this.group.getElementsByClassName("details__content");    
    
    // Set default settings if necessary
    this.settings = Object.assign({
      speed: 300,
      one_visible: false
    }, settings);
    
    // Setup inital positions
    for (let i = 0; i < this.details.length; i++) {
      const detail  = this.details[i];
      const toggle  = this.toggles[i];
      const content = this.contents[i];
      
      // Set transition-duration to match JS setting
      detail.style.transitionDuration = this.settings.speed + "ms";
      
      // Set initial height to transition from
      if (!detail.hasAttribute("open")) {
        detail.style.height = toggle.clientHeight + "px";
      } else {
        detail.style.height = toggle.clientHeight + content.clientHeight + "px";
      }
    }
    
    // Setup click handler
    this.group.addEventListener("click", (e) => {      
      if (e.target.classList.contains("details__summary")) {
        e.preventDefault();
        
        let num = 0;
        for (let i = 0; i < this.toggles.length; i++) {
          if (this.toggles[i] === e.target) {
            num = i;
            break;
          }
        }
        
        if (!e.target.parentNode.hasAttribute("open")) {
          this.open(num);
        } else {
          this.close(num);
        }
      }
    });
  }
  
  open(i) {
    const detail = this.details[i];
    const toggle = this.toggles[i];
    const content = this.contents[i];
    
    // If applicable, hide all the other details first
    if (this.settings.one_visible) {
      for (let a = 0; a < this.toggles.length; a++) {
        if (i !== a) this.close(a);
      }
    }
    
    // Update class
    detail.classList.remove("is-closing");
    
    // Get height of toggle
    const toggle_height = toggle.clientHeight;
    
    // Momentarily show the contents just to get the height
    detail.setAttribute("open", true);
    const content_height = content.clientHeight;
    detail.removeAttribute("open");
    
    // Set the correct height and let CSS transition it
    detail.style.height = toggle_height + content_height + "px";
    
    // Finally set the open attr
    detail.setAttribute("open", true);
  }
  
  close(i) {
    const detail = this.details[i];
    const toggle = this.toggles[i];
    
    // Update class
    detail.classList.add("is-closing");
    
    // Get height of toggle
    const toggle_height = toggle.clientHeight;
    
    // Set the height so only the toggle is visible
    detail.style.height = toggle_height + "px";
    
    setTimeout(() => {
      // Check if still closing
      if (detail.classList.contains("is-closing"))
        detail.removeAttribute("open");
        detail.classList.remove("is-closing");
    }, this.settings.speed);
  }
}

(() => {
  const els = document.getElementsByClassName("details-group");
  
  for (let i = 0; i < els.length; i++) {
    const details = new Details(els[i], {
      speed: 500,
      one_visible: true
    });
  }
})();
            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.
Loading ..................

Console