<h1>Fork: Playing with CSS Grid <code>auto-fit</code> and <code>grid-auto-flow</code></h1>

<p>
  This pen is forked from <a href="https://codepen.io/basherkev/pen/rNwpwgP">the example</a> used in the CSS-Tricks article <cite><a href="https://css-tricks.com/expandable-sections-within-a-css-grid/">Expandable Sections Within a CSS Grid</a></cite>. I made the following changes:
</p>

<ul>
  <li>Removed the <code>region</code> role, which did nothing without an accName;</li>
  <li>Added <code>aria-expanded</code> to the trigger so it conveys its purpose (else a likely 4.1.2 failure);</li>
  <li>Removed the live region, which is problematic since it double-announced (once from the live region, once from setting focus to it) and does not convey structure of children;</li>
  <li>Re-wrote function (my code is meh) to focus only on toggling <code>aria-expanded</code> and the one class already in use;</li>
  <li>Amended function for each button to act as its own disclosure toggle;</li>
  <li>Removed close buttons in each expanded area, though if testing with users tells you they should be there, then restore them;</li>
  <li>Added feature to script to allow you to open new items without closing other items (toggle the button following this list);</li>
  <li>Set the always-visible grid items to the same minimum height (looked weird at two columns and <code>grid-auto-rows</code> on the grid container made everything resize when the new content was shown).</li>
</ul>


<p class="toggles">
  <button type="button" id="multi" aria-pressed="false" onclick="toggle(this.id);">
    Allow multiple cards to be expanded
  </button>
</p>


<p>
  There is more information about <a href="https://adrianroselli.com/2020/05/disclosure-widgets.html">disclosure widgets</a> on my site, a <a href="https://codepen.io/aardrian/pen/NWpoVQd">sample toggle tip</a> (which is almost this but without the nifty grid layout, and it closes on <kbd>Esc</kbd>), and <a href="https://adrianroselli.com/2019/06/link-disclosure-widget-navigation.html">dislosure widgets as an accessible navigation pattern</a>.
</p>


<div>
    <ul class="grid">
        <li>
            <p>1</p>
        </li>
        <li>
            <p>2</p>
            <button type="button" id="btnDisc02" aria-expanded="false" onclick="toggleDisclosure(this.id);" aria-controls="Disclosed02">Quick view</button>
        </li>
        <li class="fullwidth is-hidden" id="Disclosed02">
            <p>fullwidth 2</p>
            <p>This grid item needs to stretch the full width of the page, and force other grid items to reflow around it, whilst remaining "visually connected" to the preceeding grid item.</p>
          <p>Test <a href="#">inline link</a>.</p>
        </li>
        <li>
            <p>3</p>
        </li>
        <li>
            <p>4</p>
            <button type="button" id="btnDisc04" aria-expanded="false" onclick="toggleDisclosure(this.id);" aria-controls="Disclosed04">Quick view</button>
        </li>
        <li class="fullwidth is-hidden" id="Disclosed04">
            <p>fullwidth 4</p>
            <p>This grid item needs to stretch the full width of the page, and force other grid items to reflow around it, whilst remaining "visually connected" to the preceeding grid item.</p>
          <p>Test <a href="#">inline link</a>.</p>
        </li>
        <li>
            <p>5</p>
            <button type="button" id="btnDisc05" aria-expanded="false" onclick="toggleDisclosure(this.id);" aria-controls="Disclosed05">Quick view</button>
        </li>
        <li class="fullwidth is-hidden" id="Disclosed05">
            <p>fullwidth 5</p>
            <p>This grid item needs to stretch the full width of the page, and force other grid items to reflow around it, whilst remaining "visually connected" to the preceeding grid item.</p>
          <p>Test <a href="#">inline link</a>.</p>
        </li>
        <li>
            <p>6</p>
        </li>
        <li>
            <p>7</p>
        </li>
        <li>
            <p>8</p>
        </li>
    </ul>
</div>
ul[class] {
    margin: 0;
    padding: 0;
}

ul[class] li {
    list-style: none;
}

ul[class] li > * {
    margin: 1rem;
}

:focus {
    box-shadow: 0 0 0 0.25rem rebeccapurple;
    outline: 0;
}

/* [1] 'auto-fit' grid columns, so no media queries required. */
/* [2] 'dense' packing fills in holes earlier in the grid. */
.grid {
    display: grid;
    gap: 1rem;
    grid-auto-flow: dense; /* [2] */
    grid-template-columns: repeat(auto-fit, 20rem); /* [1] */
    justify-content: center;
/*  AAR: Will not work well with expanded data, so do not use  */
/*     grid-auto-rows: 7rem; */
}

.grid > * {
    align-items: flex-start;
    background: #eee;
    display: flex;
    flex-direction: column;
    height: 100%;
/*  AAR: added so all items are same height (try with two cols)  */
    min-height: 7rem;
}

/* [3] Make fullwidth card span all grid columns. */
.fullwidth {
    grid-column: 1 / -1;
}

.is-hidden {
    display: none;
}

.fullwidth,
.is-selected {
    background: wheat;
}




/* I just dumped this in from another pen, */
/* it is over-engineered for this case so */
/* you should probably ignore it. */

/* Toggle */
/* https://adrianroselli.com/2019/08/under-engineered-toggles-too.html */

.toggles {
/*   margin: 0;
  padding: .5em 2em 1em 2em;
  border-bottom: .1em solid #ccc;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  background-color: #fff; */
}

.toggles [aria-pressed] {
  display: block;
  box-sizing: border-box;
  border: none;
  color: inherit;
  background: none;
  font: inherit;
  line-height: inherit;
  text-align: left;
  padding: .4em 0 .4em 4em;
  position: relative;
}

.toggles [aria-pressed][disabled],
.toggles [aria-pressed][disabled]:hover {
  color: #999;
}

.toggles [aria-pressed]:focus,
.toggles [aria-pressed]:hover {
  color: #00f;
  outline: none;
}

.toggles [aria-pressed]:focus::before,
.toggles [aria-pressed]:hover::before {
  box-shadow: 0 0 0.5em #333;
}

.toggles [aria-pressed]:focus::after,
.toggles [aria-pressed]:hover::after {
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='50' cy='50' r='50' fill='rgba(0,0,0,.25)'/%3E%3C/svg%3E");
  background-size: 30%;
  background-repeat: no-repeat;
  background-position: center center;
}

.toggles [aria-pressed]::before,
.toggles [aria-pressed]::after {
  content: "";
  position: absolute;
  height: 1.5em;
  transition: all 0.25s ease;
}

.toggles [aria-pressed]::before {
  left: 0;
  top: 0.2em;
  width: 3em;
  border: 0.2em solid #767676;
  background: #767676;
  border-radius: 1.1em;
}

.toggles [aria-pressed]::after {
  left: 0;
  top: 0.25em;
  background-color: #fff;
  background-position: center center;
  border-radius: 50%;
  width: 1.5em;
  border: 0.15em solid #767676;
}

.toggles [aria-pressed=true]::after {
  left: 1.6em;
  border-color: #36a829;
  color: #36a829;
}

.toggles [aria-pressed=true]::before {
  background-color: #36a829;
  border-color: #36a829;
}

.toggles [aria-pressed][disabled]::before {
  background-color: transparent;
  border-color: #ddd;
}

.toggles [aria-pressed][disabled]::after {
  border-color: #ddd;
}

.toggles [aria-pressed][disabled]:hover {
  color: #999; /* case for CSS custom property if not supporting IE/Edge */
}

.toggles [aria-pressed][disabled]:hover::before {
  box-shadow: none;
}

.toggles [aria-pressed][disabled]:hover::after {
  background-image: none;
}

/* Put toggles on the right like the iOS the kids like */

.toggles.flip [aria-pressed]::before,
.toggles.flip [aria-pressed]::after {
  left: auto;
  right: 0;
}

.toggles.flip [aria-pressed]::after {
  left: auto;
  right: 1.6em;
}

.toggles.flip [aria-pressed=true]::after {
  right: 0;
}

.toggles.flip [aria-pressed] {
  padding-left: 0;
  padding-right: 4em;
}

/* Windows High Contrast Mode Support */
@media screen and (-ms-high-contrast: active) {
  .toggles [aria-pressed]:focus::before,
  .toggles [aria-pressed]:hover::before {
    outline: 1px dotted windowText;
    outline-offset: 0.25em;
  }
  .toggles [aria-pressed]::after {
    background-color: windowText;
  }
  .toggles [aria-pressed][disabled]::after {
    background-color: transparent;
  }
}

/* Reduced motion */
@media screen and (prefers-reduced-motion: reduce) {
  .toggles [aria-pressed]::before,
  .toggles [aria-pressed]::after {
    transition: none;
  }
}


/* RTL */
/* https://twitter.com/dror3go/status/1102946375396982784 */
*[dir="rtl"] .toggles [aria-pressed] {
  padding-left: 0;
  padding-right: 4em;
}

*[dir="rtl"] .toggles [aria-pressed]::before,
*[dir="rtl"] .toggles [aria-pressed]::after {
  left: auto;
  right: 0;
}

*[dir="rtl"] .toggles [aria-pressed]::after {
  right: 0;
}

*[dir="rtl"] .toggles [aria-pressed=true]::after {
  right: 1.6em;
}

/* Put toggles on the right like the iOS the kids like */

*[dir="rtl"] .toggles.flip [aria-pressed]::before,
*[dir="rtl"] .toggles.flip [aria-pressed]::after {
  left: 0;
  right: auto;
}

*[dir="rtl"] .toggles.flip [aria-pressed]::after {
  right: auto;
  left: 1.6em;
}

*[dir="rtl"] .toggles.flip [aria-pressed=true]::after {
  left: 0;
}

*[dir="rtl"] .toggles.flip [aria-pressed] {
  padding-right: 0;
  padding-left: 4em;
}
// For the ability to choose if multiple cards
// can be expanded at the same time.
var CloseAll = true;

function toggleDisclosure(btnID) {
  // Change value to false if you want each opened view
  // to stay open as you open more (test the grid).
  // var CloseAll = true;
  if (CloseAll == true) {
    toggleAll(btnID);
  } else {
    toggleOne(btnID);
  }
}

function toggleAll(btnID) {  
  // Get the button that triggered this
  var theButton = document.getElementById(btnID);
  // Get its state
  var theButtonState = theButton.getAttribute("aria-expanded");
  // Get the value of the aria-controls attribute
  var strControls = theButton.getAttribute("aria-controls");
  // Find the node with that id
  var theDisclosee = document.getElementById(strControls);
  // Get all the disclosure buttons
  var allButtons = document.querySelectorAll("[aria-expanded]");
  // Get all the disclosure content
  var allDisclosees = document.querySelectorAll(".fullwidth");
  // Loop through all buttons and mark as closed
  for (var i = 0; i < allButtons.length; i++) {
    allButtons[i].setAttribute("aria-expanded", "false");
  }
  // Loop through all disclosees and add hidden class
  for (var i = 0; i < allDisclosees.length; i++) {
    allDisclosees[i].classList.add('is-hidden');
  }
  // If the button was not expanded...
  if (theButtonState == "false") {
    // Now set the button to expanded
    theButton.setAttribute("aria-expanded", "true");
    // Remove the is-hidden class
    theDisclosee.classList.remove('is-hidden');
  // Otherwise button was expanded...
  } else {
    // Now set the button to collapsed
    theButton.setAttribute("aria-expanded", "false");
    // Add the class that hides the content
    theDisclosee.classList.add('is-hidden');
  }
}

function toggleOne(btnID) {
  // Get the button that triggered this
  var theButton = document.getElementById(btnID);
  // Get the value of the aria-controls attribute
  var strControls = theButton.getAttribute("aria-controls");
  // Find the node with that id
  var theDisclosee = document.getElementById(strControls);
  // If the button is not expanded...
  if (theButton.getAttribute("aria-expanded") == "false") {
    // Now set the button to expanded
    theButton.setAttribute("aria-expanded", "true");
    // Remove the is-hidden class
    theDisclosee.classList.remove('is-hidden');
  // Otherwise button is expanded...
  } else {
    // Now set the button to collapsed
    theButton.setAttribute("aria-expanded", "false");
    // Add the class that hides the content
    theDisclosee.classList.add('is-hidden');
  }
}



// Just for the toggle control I added. It has no
// bearing on the card display thinger.
function toggle(btnID) {
  var theButton = document.getElementById(btnID);
  if (theButton.getAttribute("aria-pressed") == "false") {
    theButton.setAttribute("aria-pressed", "true");
    CloseAll = false;
  } else {
    theButton.setAttribute("aria-pressed", "false");
    CloseAll = true;
  }
}
Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.