UNIT 21 • STAGE 4 OF 7

Read More Toggle

Your first JavaScript toggle: classList, addEventListener, textContent

UNIT 4 / 7
STEP 1

The Toggle Pattern

You have already written JavaScript that uses addEventListener and style.display to show and hide things. In Unit 9 you showed a thank-you message when a form was submitted. In Unit 10 you opened a modal when a card was clicked.

This stage teaches a cleaner version of that same idea: the toggle. Instead of setting style.display directly, you will use classList.toggle() to add or remove a CSS class. The CSS class controls the visual change. JavaScript only controls which class is present. This separation, JavaScript handles state, CSS handles appearance, is how real websites are built.

You will also change the button label when the state changes: "Read More" becomes "Read Less" when the card is expanded, and returns to "Read More" when it collapses. This uses the textContent property you used in Unit 10.

The Three Lines That Matter

The core logic is three lines: var card = this.closest('.author-card') gets the parent card. card.classList.toggle('expanded') adds the class if it is absent, removes it if it is present. this.textContent = card.classList.contains('expanded') ? 'Read Less' : 'Read More' updates the button label based on the current state.

STEP 2

Add the Toggle CSS

Add two new rules to your CSS, after the .author-card-bio rule. The first removes the line clamp when the card is expanded. The second styles the button.

👉 Add these two CSS rules after .author-card-bio:     .author-card.expanded .author-card-bio {
      -webkit-line-clamp: unset;
      overflow: visible;
    }

    .read-more-btn {
      background: none;
      border: none;
      color: #6b9bd1;
      font-family: 'Fredoka', sans-serif;
      font-size: 0.9375rem;
      font-weight: 600;
      cursor: pointer;
      padding: 8px 0 0;
      display: block;
    }
    .read-more-btn:hover { color: #4a7ab5; }
STEP 3

Add the Button to Each Card

Inside each .author-card, add a Read More button after the .author-card-bio paragraph. You need to do this for all six cards. Here is the line to add:

👉 Add this inside each .author-card, after the bio paragraph: <button class="read-more-btn">Read More</button>

Each card will then look like this structure:

Pattern, each card: <div class="author-card">
  <h3 class="author-card-name">...</h3>
  <p class="author-card-nation">...</p>
  <p class="author-card-bio">...</p>
  <button class="read-more-btn">Read More</button>
</div>
STEP 4

Write the JavaScript

Now add a <script> tag just before the closing </body> tag and write the toggle. This is the main JavaScript concept in Unit 21. Read each line carefully before typing it.

👉 Add this before </body>: <script>
  // Select every Read More button on the page
  document.querySelectorAll('.read-more-btn').forEach(function(btn) {

    // When this button is clicked...
    btn.addEventListener('click', function() {

      // Find the parent .author-card
      var card = this.closest('.author-card');

      // Toggle the 'expanded' class on the card
      card.classList.toggle('expanded');

      // Update button label based on current state
      this.textContent = card.classList.contains('expanded')
        ? 'Read Less'
        : 'Read More';
    });
  });
</script>
STEP 5

Why This Works

  • querySelectorAll('.read-more-btn'): selects all six buttons at once and returns a NodeList. You used this same method in Unit 10 for the modal cards.
  • .forEach(function(btn) { ... }): runs the same code for each button. Each button gets its own event listener attached.
  • this.closest('.author-card'): inside an event listener, this refers to the element that was clicked, which is the button. closest() walks up the DOM tree looking for the nearest ancestor that matches the selector. Since the button is inside .author-card, this gives us the card.
  • classList.toggle('expanded'): if expanded is not on the card, it adds it. If it is already there, it removes it. One line, both directions.
  • card.classList.contains('expanded') ? 'Read Less' : 'Read More': a ternary expression. Read it as: if the card has the expanded class, set label to "Read Less", otherwise set it to "Read More". This updates the button text to match the current state every time it is clicked.
  • .author-card.expanded .author-card-bio in CSS: the CSS does the actual visual work. When expanded is present on the card, the bio's line clamp is removed and overflow is restored to visible. JavaScript only toggles the class. CSS handles the appearance.

Stage 4 Complete

Test it: click Read More on any author card. The bio should expand and the button should say "Read Less." Click again to collapse. In Stage 5 you will build a book gallery using CSS Grid and the aspect-ratio property.

Code Editor
Live Preview