The previous lesson stored your skills as an array. This lesson walks that array with for…of and builds the skill cards on the page from the data.
The concept
Here is your page with the skills array already in the script. Run it:
▸WHAT'S ALREADY IN THIS PAGE
New here? This starter already carries the standard HTML frame. You do not need to change it to do the exercise — each piece is taught in its own lesson.
<!DOCTYPE html>— Tells the browser to use modern rendering rules. Taught in lesson 2.<html> … </html>— The root element that wraps the whole document. Taught in lesson 2.lang="en"— Sets the page's language. Taught in lesson 6.<head>— Holds information about the page; nothing in it is drawn on screen. Taught in lesson 2.<meta charset="UTF-8" />— Sets how the browser decodes the text. Taught in lesson 6.<title>— Sets the browser-tab text. Taught in lesson 2.<body>— Holds everything a visitor actually sees. Taught in lesson 2.<script>— Holds JavaScript for the page. Taught in lesson 23.
The CONSOLE still shows the length and the first skill. The three cards in Skills are still hard-coded HTML. You are about to make the list come from the array.
Run this tiny page:
▸WHAT'S ALREADY IN THIS PAGE
New here? This starter already carries the standard HTML frame. You do not need to change it to do the exercise — each piece is taught in its own lesson.
<!DOCTYPE html>— Tells the browser to use modern rendering rules. Taught in lesson 2.<html> … </html>— The root element that wraps the whole document. Taught in lesson 2.lang="en"— Sets the page's language. Taught in lesson 6.<head>— Holds information about the page; nothing in it is drawn on screen. Taught in lesson 2.<meta charset="UTF-8" />— Sets how the browser decodes the text. Taught in lesson 6.<title>— Sets the browser-tab text. Taught in lesson 2.<body>— Holds everything a visitor actually sees. Taught in lesson 2.<script>— Holds JavaScript for the page. Taught in lesson 23.
Three cards appear. The HTML list started empty. The script created each li, set its text, and appended it. Click a card: the CONSOLE prints that skill. Each handler was wired inside the same loop pass that built the card.
for (const skill of skills) walks the array. On each pass, skill holds one string. The block runs once per item.
Building one element looks like this:
▸WHAT'S ALREADY IN THIS PAGE
New here? This starter already carries the standard HTML frame. You do not need to change it to do the exercise — each piece is taught in its own lesson.
<!DOCTYPE html>— Tells the browser to use modern rendering rules. Taught in lesson 2.<html> … </html>— The root element that wraps the whole document. Taught in lesson 2.lang="en"— Sets the page's language. Taught in lesson 6.<head>— Holds information about the page; nothing in it is drawn on screen. Taught in lesson 2.<meta charset="UTF-8" />— Sets how the browser decodes the text. Taught in lesson 6.<title>— Sets the browser-tab text. Taught in lesson 2.<body>— Holds everything a visitor actually sees. Taught in lesson 2.<script>— Holds JavaScript for the page. Taught in lesson 23.
document.createElement("li") makes a new list item in memory. textContent sets the visible text. append puts that item into the list on the page.
This path uses textContent, not innerHTML, for the card text.
The syntax
const skills = ["HTML", "CSS", "JavaScript"];
const skillRow = document.querySelector(".skill-row");
for (const skill of skills) {
const item = document.createElement("li");
item.classList.add("skill-card");
item.textContent = skill;
item.addEventListener("click", function () {
console.log(skill);
});
skillRow.append(item);
}for (const value of array) runs the block once per item.
createElement builds an element. append attaches it.
A function defined inside the loop keeps that pass's variables, so each card's handler remembers its own skill.
Give each card the skill-card class so your existing CSS still applies.
A minimal working example
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Skills from a loop</title>
</head>
<body>
<ul class="skill-row"></ul>
<script>
const skills = ["HTML", "CSS", "JavaScript"];
const skillRow = document.querySelector(".skill-row");
for (const skill of skills) {
const item = document.createElement("li");
item.classList.add("skill-card");
item.textContent = skill;
item.addEventListener("click", function () {
console.log(skill);
});
skillRow.append(item);
}
</script>
</body>
</html>An empty list in the markup. A loop that fills it. One card per array item.
Common mistakes
You leave the hard-coded cards and also append. Run this:
▸WHAT'S ALREADY IN THIS PAGE
New here? This starter already carries the standard HTML frame. You do not need to change it to do the exercise — each piece is taught in its own lesson.
<!DOCTYPE html>— Tells the browser to use modern rendering rules. Taught in lesson 2.<html> … </html>— The root element that wraps the whole document. Taught in lesson 2.lang="en"— Sets the page's language. Taught in lesson 6.<head>— Holds information about the page; nothing in it is drawn on screen. Taught in lesson 2.<meta charset="UTF-8" />— Sets how the browser decodes the text. Taught in lesson 6.<title>— Sets the browser-tab text. Taught in lesson 2.<body>— Holds everything a visitor actually sees. Taught in lesson 2.<script>— Holds JavaScript for the page. Taught in lesson 23.
Six cards appear. The original three stayed in the HTML. The loop added three more. Remove the three hard-coded <li> elements from .skill-row so the list starts empty before the loop runs.
You append to the wrong container. You select #skills or body instead of .skill-row. New items land outside the flex row, or nested under the section heading. Select the ul with class skill-row, the same list that held the hard-coded cards.
You reach for innerHTML to inject the skill string. Putting text that people typed into innerHTML is unsafe, and the safe pattern comes later. For this lesson, set textContent on an element you created.
Try it yourself
Render your skill cards from the array. Confirm each step in the preview. After each Run, scroll the preview to Skills if you do not see the cards yet. The header and About sit above them, so the list can land below the fold.
- Run the starting code below. Confirm the change-tagline and theme-toggle buttons still work. Scroll the preview to Skills if you do not see it yet. Confirm Skills still shows the hard-coded cards (one per skill name in the HTML), and the CONSOLE still shows the array length and first skill.
- In the HTML, delete every
<li class="skill-card">line inside.skill-row, leaving an empty<ul class="skill-row"></ul>. Do not add a new list. Run it. Scroll to Skills. Confirm the Skills section has a heading and no cards yet. - Below your skills array logs in the script, select
.skill-rowinto a variable. Write afor (const skill of skills)loop that creates anli, adds the classskill-cardwithclassList.add, setstextContenttoskill, listens for"click"with a function thatconsole.logsskill, andappends the item to the list. Run it. Scroll to Skills. Confirm the cards return, one per item in yourskillsarray. Click each card. Confirm the CONSOLE prints that card's own skill string. - Change one string in the
skillsarray and Run again. Scroll to Skills. Confirm the cards follow the array, not old hard-coded HTML. - Break it on purpose: put the hard-coded
<li>elements back into the HTML while leaving the loop in place. Run it. Scroll to Skills. Confirm twice as many cards as the array alone (original HTML cards plus the loop). Remove the hard-coded items again and confirm one card per array item.
▸WHAT'S ALREADY IN THIS PAGE
New here? This starter already carries the standard HTML frame. You do not need to change it to do the exercise — each piece is taught in its own lesson.
<!DOCTYPE html>— Tells the browser to use modern rendering rules. Taught in lesson 2.<html> … </html>— The root element that wraps the whole document. Taught in lesson 2.lang="en"— Sets the page's language. Taught in lesson 6.<head>— Holds information about the page; nothing in it is drawn on screen. Taught in lesson 2.<meta charset="UTF-8" />— Sets how the browser decodes the text. Taught in lesson 6.<title>— Sets the browser-tab text. Taught in lesson 2.<body>— Holds everything a visitor actually sees. Taught in lesson 2.<script>— Holds JavaScript for the page. Taught in lesson 23.
Your skill cards now come from the array. The next lesson groups labeled fields into objects, including turning each skill into an object with a name.