UNIT 21 • STAGE 4 OF 7
Your first JavaScript toggle: classList, addEventListener, textContent
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 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.
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.
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:
Each card will then look like this structure:
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.
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.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.