Build an Interactive Tech Profile
Build a responsive profile page with HTML, CSS, and JavaScript theme controls.
Introduction
30 Second Summary
When someone asks what you are learning in tech, a spoken answer disappears as soon as the conversation ends. A webpage gives your progress a place to live and grow.
In this project, you will build a personal Tech Starter Profile Page using HTML, CSS, and JavaScript. Its theme switcher will change the page between light and dark themes.
What You'll Build
Picture opening your profile in Microsoft Edge to show your introduction, your learning goals, and a theme that changes across the whole page with one click.
By the end of this project, you'll have:
- A customizable profile card that presents your introduction beside the technologies you want to learn.
- A responsive layout that stays readable when you narrow the browser window.
- A working theme switcher that updates the page colors, its own label, and a visible status message.
- Secret Mission: Add an HTML progress control that marks your first skill as learned and changes the card's appearance.
Are there any prerequisites?
You need Visual Studio Code and Microsoft Edge installed on Windows. Both tools are already available in your learner environment, so there is nothing else to install.
Before We Start
First, let’s lock in what you’re building so every change has a clear purpose. You’re creating a Tech Starter Profile Page that introduces Alex and presents HTML, CSS, and JavaScript as learning goals.
Set Up Your Project Workspace
A dedicated project folder keeps your page’s HTML, CSS, and JavaScript together as the profile grows.
In this step, you will create that folder in Visual Studio Code. You will also open a small HTML success in Microsoft Edge before the main build begins.
In this step, get ready to:
- Open a trusted workspace for your profile page.
- Create the three project files with a starter HTML document.
- Display your first heading in Microsoft Edge.
Create a trusted project folder
The folder becomes the home for every part of your profile page. Opening it as a workspace also lets the Explorer sidebar keep all three files within reach.
- Press the Windows key to open the search bar.
- Type Visual Studio Code and press Enter to open it.
You’ll see the Visual Studio Code editor ready for a workspace.
- Click File in the top menu bar.
- Select Open Folder....
The folder picker is now ready for you to choose where the project lives.
- Select your Desktop in the folder picker.
- Use the folder picker’s folder creation control to create tech-starter-page on the Desktop.
You should see the new tech-starter-page folder in the folder picker.
- Select the tech-starter-page folder.
- Click Select Folder.
Visual Studio Code opens the folder as your workspace. The Explorer sidebar shows TECH-STARTER-PAGE at the top.
- Click Yes, I trust the authors if Workspace Trust appears.
Your workspace is ready. Every file you add next stays grouped inside the folder you created.
Folder not showing in Explorer?
Check that the Explorer sidebar names TECH-STARTER-PAGE. Select File followed by Open Folder... again if a different folder opened.
Ask for help if the workspace still looks different. Help me open my tech-starter-page folder as a trusted workspace in Visual Studio Code on Windows.
Create the project files
Each file has one job. The HTML holds the content while the empty styling and behavior files reserve space for later steps.
- Click New File... in the Explorer sidebar.
- Enter index.html and press Enter.
You’ll see index.html in the Explorer sidebar. Its empty editor opens beside the sidebar.
- Click New File... in the Explorer sidebar.
- Enter style.css and press Enter.
The Explorer sidebar now lists index.html with style.css.
- Click New File... in the Explorer sidebar.
- Enter app.js and press Enter.
All three project files are now visible in the Explorer sidebar.
- Select index.html in the Explorer sidebar.
- Add the starter document by pasting this code:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Tech Starter Page</title>
</head>
<body>
<h1>My Tech Starter Page</h1>
</body>
</html>
What does this code do?
- The <!doctype html> line tells the browser to interpret this file as a modern HTML document.
- The <head> stores page information that supports the browser tab and narrow screens.
- The <body> contains the visible heading that proves the local page works.
- Save index.html by pressing Ctrl+S.
- Check the Explorer sidebar.
You should see index.html, style.css, and app.js inside TECH-STARTER-PAGE.
Code showing as plain text?
Confirm that the file is named index.html with no extra file extension. Compare the opening and closing angle brackets with the code above if Visual Studio Code highlights an HTML problem.
Ask for help if the document still looks different. Help me compare my starter index.html file with the required Tech Starter Page document.
✔️ Awesome, I've got everything!
Great. Double check that index.html is saved. Keep style.css with app.js completely empty for now.
ⓧ I'd like to double check the full code
Your complete index.html should match this file exactly.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Tech Starter Page</title>
</head>
<body>
<h1>My Tech Starter Page</h1>
</body>
</html>
Your style.css file should be completely empty. Your app.js file should also be completely empty.
Open the starter page in Microsoft Edge
A browser can open this HTML file directly from your computer. Seeing the heading confirms that the workspace and starter document are connected correctly.
- Press the Windows key to open the search bar.
- Type Microsoft Edge and press Enter to open it.
Microsoft Edge opens with a browser window ready for your local file.
Before you open the file, what heading do you expect Microsoft Edge to display?
- Press Ctrl+O in Microsoft Edge.
- Double-click tech-starter-page on your Desktop.
- Double-click index.html.
You’ll see the heading “My Tech Starter Page” on a plain white page. That is your first browser result working from the new workspace.
Don’t see the heading?
Return to Visual Studio Code and confirm that index.html contains the heading. Press Ctrl+S before opening the file again.
Check that Microsoft Edge opened the index.html inside tech-starter-page. Help me find why my local index.html file does not show the My Tech Starter Page heading in Microsoft Edge.
Your three-file workspace is ready. Next, you’ll replace the starter heading with the full profile structure and its first visible controls.
Build the Profile Page Structure
Your Visual Studio Code workspace now contains the three files for your page. Microsoft Edge confirms that your starter document works.
A single heading cannot introduce you or show your learning goals. This step gives the page a semantic HTML structure that the browser can display before design or behavior is added.
In this step, get ready to:
- Build the introduction inside a profile card.
- Add three cards for your learning goals.
- Add the theme controls and connect the support files.
Build the profile card
Semantic elements describe the purpose of each part of a webpage. The profile card starts with a main content area that contains your introduction.
- Select index.html in the Visual Studio Code Explorer sidebar.
- Find the existing <h1>My Tech Starter Page</h1> line.
- Replace that line with the profile introduction by pasting this code:
<main class="profile-card">
<header class="intro">
<p class="eyebrow">MY FIRST WEB PROJECT</p>
<h1>Hi, I’m Alex</h1>
<p class="bio">
I’m starting my journey in tech and building one small project at a time.
</p>
</header>
</main>
What does this code do?
- The <main> element holds the page's primary content.
- The <header> element groups the introductory content.
- The class names give each element a precise target for styling later.
- Save index.html by pressing Ctrl+S.
- Switch back to Microsoft Edge from earlier.
- Refresh the local page by pressing Ctrl+R.
You'll see the starter heading replaced by Alex's introduction. Your first content section now has a clear purpose.
Still seeing the starter heading?
- Confirm that you saved index.html after replacing the original heading.
- Check that the local page in Microsoft Edge came from the tech-starter-page folder.
help me find why my updated index.html is not appearing in Microsoft Edge.
The introduction tells visitors who the page is about. A separate learning section turns HTML, CSS, and JavaScript into three visible goals.
- Switch back to index.html in Visual Studio Code.
- Find the closing </header> tag.
- Add the learning section below that tag by pasting this code:
<section aria-labelledby="learning-title">
<h2 id="learning-title">What I’m learning</h2>
<div class="skills">
<article class="skill">
<h3>HTML</h3>
<p>Structures the content on a webpage.</p>
</article>
<article class="skill">
<h3>CSS</h3>
<p>Controls the page’s colors, spacing, and layout.</p>
</article>
<article class="skill">
<h3>JavaScript</h3>
<p>Adds behavior when someone interacts with the page.</p>
</article>
</div>
</section>
How is the learning section organized?
- The <section> element groups the learning goals under one heading.
- The skills container keeps the three cards together.
- Each <article> element represents one technology with its own explanation.
- Save index.html by pressing Ctrl+S.
- Switch back to Microsoft Edge from earlier.
- Refresh the local page by pressing Ctrl+R.
You'll see a learning heading followed by separate descriptions for HTML, CSS, and JavaScript.
Missing a learning card?
- Check that each <article> has its own closing </article> tag.
- Confirm that the learning section sits between </header> and </main>.
help me fix a missing learning card in my HTML structure.
Add the theme controls and file links
The document needs entry points for its visual rules and click behavior. The stylesheet connection gives CSS a place to control the design.
The deferred script connection lets the page structure load before JavaScript runs. Both linked files remain empty during this step.
- Switch back to index.html in Visual Studio Code.
- Find the <title>My Tech Starter Page</title> line.
- Connect the existing support files below the title by pasting this code:
<link rel="stylesheet" href="style.css">
<script src="app.js" defer></script>
What do these connections do?
The <link> element connects style.css to the page. The <script> element connects app.js.
The defer attribute waits for the document to finish parsing before the script runs.
- Find the closing </section> tag.
- Add the theme button and status message below that tag by pasting this code:
<button class="theme-button" type="button">Switch to dark theme</button>
<p class="status" aria-live="polite">Light theme is active.</p>
What do the controls provide?
The button gives visitors a visible theme control. Its theme-button class provides a target for styling and behavior.
The status message states which theme is active. Its aria-live attribute allows future text updates to be announced by supporting assistive technology.
- Save index.html by pressing Ctrl+S.
- Switch back to Microsoft Edge from earlier.
- Refresh the local page by pressing Ctrl+R.
You'll see Alex's bio followed by three learning cards. You'll also see the theme button above the light-theme status.
Before you click the theme button, which parts of the page do you expect to react?
- Click Switch to dark theme in Microsoft Edge.
You'll see that the colors, button label, and status message stay the same. That limitation is intentional because the page has no click behavior yet.
Don't see the full profile?
- Confirm that the button and status message appear after the closing </section> tag.
- Check that every new element remains inside the <main class="profile-card"> element.
- Refresh the local page again after saving index.html.
help me find why my profile page content is incomplete in Microsoft Edge.
✔️ Awesome, I've got everything!
You now have the complete page structure. The visible button also proves exactly where interaction is still missing.
- Confirm that index.html is saved before moving on.
ⓧ I'd like to double check the full code
Compare your index.html with the complete file below. Your style.css and app.js files should still be empty.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Tech Starter Page</title>
<link rel="stylesheet" href="style.css">
<script src="app.js" defer></script>
</head>
<body>
<main class="profile-card">
<header class="intro">
<p class="eyebrow">MY FIRST WEB PROJECT</p>
<h1>Hi, I’m Alex</h1>
<p class="bio">
I’m starting my journey in tech and building one small project at a time.
</p>
</header>
<section aria-labelledby="learning-title">
<h2 id="learning-title">What I’m learning</h2>
<div class="skills">
<article class="skill">
<h3>HTML</h3>
<p>Structures the content on a webpage.</p>
</article>
<article class="skill">
<h3>CSS</h3>
<p>Controls the page’s colors, spacing, and layout.</p>
</article>
<article class="skill">
<h3>JavaScript</h3>
<p>Adds behavior when someone interacts with the page.</p>
</article>
</div>
</section>
<button class="theme-button" type="button">Switch to dark theme</button>
<p class="status" aria-live="polite">Light theme is active.</p>
</main>
</body>
</html>
How should the finished file behave?
This file displays the introduction, learning cards, button, and status message. The empty support files mean the content remains unstyled and the button remains unresponsive.
You have turned one starter heading into a complete profile with a deliberate interaction gap. Next, you'll use CSS to turn this plain content into a responsive card.
Style the Profile Card
Your profile content now appears in Microsoft Edge. That visible page proves your HTML structure works.
The browser gives every part a plain default appearance. CSS creates the visual hierarchy that guides someone through your profile.
You will add color, spacing, borders, shadows, and a responsive layout. The theme button stays unresponsive until JavaScript supplies its behavior.
In this step, get ready to:
- Create the light-theme page foundation.
- Turn the profile content into a polished card.
- Make the skill grid responsive on narrow screens.
Create the light-theme foundation
CSS custom properties give important colors reusable names. The page can use those names across several selectors.
- Switch back to Visual Studio Code.
- Select style.css in the Explorer sidebar.
- Add the shared color palette plus centered page layout with this code:
:root {
--page-background: #eef2ff;
--card-background: #ffffff;
--text-color: #172033;
--muted-text: #56627a;
--accent-color: #4f46e5;
--accent-hover: #3730a3;
--border-color: #d9def0;
--shadow-color: rgba(44, 52, 82, 0.16);
}
* {
box-sizing: border-box;
}
body {
min-height: 100vh;
margin: 0;
padding: 24px;
display: grid;
place-items: center;
font-family: "Segoe UI", Tahoma, sans-serif;
color: var(--text-color);
background: var(--page-background);
transition: color 200ms ease, background 200ms ease;
}
What Does This CSS Do?
- The :root selector stores eight reusable values for the page palette.
- The universal * selector keeps padding inside each element’s measured size.
- The body styles make the page fill the browser window.
- The grid placement centers the profile content.
- The transition softens future color changes.
- Save style.css with Ctrl+S.
- Return to Microsoft Edge.
- Refresh the page with Ctrl+R.
You should see a pale purple background with the profile content centered in the window. Your first design change is live.
Still Seeing a Plain White Page?
- Check that index.html still contains <link rel="stylesheet" href="style.css">.
- Confirm that the new CSS starts at the top of style.css.
- Save style.css again with Ctrl+S.
Help me find why style.css is not changing my local HTML page.
The page needs a second color palette for its future dark state. The profile also needs a card surface that separates it from the page background.
- Return to style.css in Visual Studio Code.
- Add the alternate palette plus profile-card styles below the body rule with this code:
body.dark-theme {
--page-background: #111827;
--card-background: #1f2937;
--text-color: #f8fafc;
--muted-text: #cbd5e1;
--accent-color: #818cf8;
--accent-hover: #a5b4fc;
--border-color: #475569;
--shadow-color: rgba(0, 0, 0, 0.35);
}
.profile-card {
width: min(760px, 100%);
padding: 40px;
background: var(--card-background);
border: 1px solid var(--border-color);
border-radius: 24px;
box-shadow: 0 18px 50px var(--shadow-color);
}
How Does the Card Take Shape?
- The body.dark-theme selector defines the alternate color values for the dark state.
- The .profile-card width stays within the browser window.
- The padding creates space around the profile content.
- The border separates the card from the page background.
- The shadow lifts the card above the page.
- Save style.css with Ctrl+S.
- Return to Microsoft Edge.
- Refresh the page with Ctrl+R.
You should see the profile content inside a white card with rounded corners. A soft shadow should separate the card from the pale background.
Card Still Looks Flat?
- Check that the selector begins with .profile-card.
- Confirm that index.html contains class="profile-card" on the main element.
- Check each opening brace for a matching closing brace.
Help me debug the profile card styles.
Build the card hierarchy
Typography guides the reader from your name to your learning goals. Differences in size plus spacing separate the introduction from the skill section.
- Return to style.css in Visual Studio Code.
- Add the introduction plus heading styles below .profile-card with this code:
.intro {
margin-bottom: 32px;
}
.eyebrow {
margin: 0 0 10px;
color: var(--accent-color);
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.12em;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
margin-bottom: 12px;
font-size: clamp(2rem, 6vw, 3.5rem);
}
h2 {
margin-bottom: 16px;
}
How Does This Create Hierarchy?
- The .intro margin separates your introduction from the learning section.
- The .eyebrow style creates a small accent label above your name.
- The shared rule removes the default top margins from headings plus paragraphs.
- The clamp() value lets your name scale with the window width.
- Save style.css with Ctrl+S.
- Return to Microsoft Edge.
- Refresh the page with Ctrl+R.
You should see a large name heading. The project label should appear smaller in the accent color.
Headings Still Look the Same?
- Check that .eyebrow includes its leading period.
- Confirm that the h1 rule closes before the h2 rule begins.
- Compare each property name with the code above.
Help me debug the profile typography styles.
The learning section needs a repeatable layout for its three cards. CSS Grid places them into equal columns with consistent gaps.
- Add the supporting text plus skill-card styles below the heading rules with this code:
.bio,
.skill p,
.status {
color: var(--muted-text);
line-height: 1.6;
}
.skills {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin-bottom: 28px;
}
.skill {
padding: 20px;
border: 1px solid var(--border-color);
border-radius: 16px;
}
.skill h3 {
margin-bottom: 8px;
}
.skill p {
margin-bottom: 0;
}
How Does the Skill Grid Work?
- The bio plus supporting text use the muted color for contrast with the headings.
- The .skills selector creates three equal columns.
- The gap keeps each card visually separate.
- Each .skill receives padding plus a rounded border.
- Save style.css with Ctrl+S.
- Return to Microsoft Edge.
- Refresh the page with Ctrl+R.
You should see three bordered skill cards in one row. The bio plus skill descriptions should use softer text than the headings.
Skill Cards Not Forming Columns?
- Check that the grid selector is .skills.
- Confirm that display: grid appears inside the .skills rule.
- Check that each card in index.html still uses class="skill".
Help me fix the three-column skill grid.
Finish the controls and responsive layout
The theme button needs clear default plus hover states so it feels clickable. A visible focus outline shows keyboard users which control is active.
- Add the theme-button plus status styles below the skill rules with this code:
.theme-button {
padding: 12px 18px;
color: #ffffff;
background: var(--accent-color);
border: 0;
border-radius: 10px;
font: inherit;
font-weight: 700;
cursor: pointer;
}
.theme-button:hover {
background: var(--accent-hover);
}
.theme-button:focus-visible {
outline: 3px solid var(--accent-hover);
outline-offset: 3px;
}
.status {
margin: 12px 0 0;
font-size: 0.9rem;
}
What Makes the Button Feel Interactive?
- The .theme-button rule creates a padded accent-colored control.
- The hover state darkens the background when the pointer rests over the button.
- The focus state adds an outline during keyboard navigation.
- The .status rule creates space below the button.
- Save style.css with Ctrl+S.
- Return to Microsoft Edge.
- Refresh the page with Ctrl+R.
- Move the pointer over the theme button.
You should see a rounded indigo button with white text. Its background should become darker when you hover over it.
Button Still Looks Like the Browser Default?
- Check that the selector is .theme-button.
- Confirm that the button in index.html still uses class="theme-button".
- Check that the hover selector includes :hover.
Help me debug the theme button CSS.
A media query applies a different layout when the browser becomes narrow. At 640px or below, one column gives each skill card more room.
- Return to style.css in Visual Studio Code.
- Add the narrow-screen rules at the bottom of style.css with this code:
@media (max-width: 640px) {
.profile-card {
padding: 26px;
}
.skills {
grid-template-columns: 1fr;
}
}
How Does the Layout Respond?
- The media query activates when the available width reaches 640px or less.
- The smaller card padding preserves room for the content.
- The one-column grid stacks the skill cards vertically.
Before you test the finished layout, how do you think the three-column grid will respond in a narrow browser window?
- Save style.css with Ctrl+S.
- Return to Microsoft Edge.
- Refresh the page with Ctrl+R.
- Drag one side of the Microsoft Edge window inward until the page is narrower than 640px.
You should see the HTML, CSS, and JavaScript cards stack into one column. The profile card should keep space around its content.
Before you click the theme button, do you think CSS can respond to the click without JavaScript?
- Click Switch to dark theme.
The page stays in its light theme. The button label plus status message remain unchanged.
That shortfall is intentional. You have proved that the polished control still needs click behavior.
Cards Stay in Three Columns?
- Check that the media query sits outside every earlier selector block.
- Confirm that the query uses max-width: 640px.
- Check that the narrow .skills rule uses grid-template-columns: 1fr.
Help me debug the responsive skill-card layout.
✔️ Awesome, I've got everything!
Your light-theme profile card is polished plus responsive. Double check that style.css is saved before moving on.
ⓧ I'd like to double check the full code
Your index.html remains unchanged from the previous step. Your app.js file remains empty.
Compare your saved style.css with this complete file.
:root {
--page-background: #eef2ff;
--card-background: #ffffff;
--text-color: #172033;
--muted-text: #56627a;
--accent-color: #4f46e5;
--accent-hover: #3730a3;
--border-color: #d9def0;
--shadow-color: rgba(44, 52, 82, 0.16);
}
* {
box-sizing: border-box;
}
body {
min-height: 100vh;
margin: 0;
padding: 24px;
display: grid;
place-items: center;
font-family: "Segoe UI", Tahoma, sans-serif;
color: var(--text-color);
background: var(--page-background);
transition: color 200ms ease, background 200ms ease;
}
body.dark-theme {
--page-background: #111827;
--card-background: #1f2937;
--text-color: #f8fafc;
--muted-text: #cbd5e1;
--accent-color: #818cf8;
--accent-hover: #a5b4fc;
--border-color: #475569;
--shadow-color: rgba(0, 0, 0, 0.35);
}
.profile-card {
width: min(760px, 100%);
padding: 40px;
background: var(--card-background);
border: 1px solid var(--border-color);
border-radius: 24px;
box-shadow: 0 18px 50px var(--shadow-color);
}
.intro {
margin-bottom: 32px;
}
.eyebrow {
margin: 0 0 10px;
color: var(--accent-color);
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.12em;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
margin-bottom: 12px;
font-size: clamp(2rem, 6vw, 3.5rem);
}
h2 {
margin-bottom: 16px;
}
.bio,
.skill p,
.status {
color: var(--muted-text);
line-height: 1.6;
}
.skills {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin-bottom: 28px;
}
.skill {
padding: 20px;
border: 1px solid var(--border-color);
border-radius: 16px;
}
.skill h3 {
margin-bottom: 8px;
}
.skill p {
margin-bottom: 0;
}
.theme-button {
padding: 12px 18px;
color: #ffffff;
background: var(--accent-color);
border: 0;
border-radius: 10px;
font: inherit;
font-weight: 700;
cursor: pointer;
}
.theme-button:hover {
background: var(--accent-hover);
}
.theme-button:focus-visible {
outline: 3px solid var(--accent-hover);
outline-offset: 3px;
}
.status {
margin: 12px 0 0;
font-size: 0.9rem;
}
@media (max-width: 640px) {
.profile-card {
padding: 26px;
}
.skills {
grid-template-columns: 1fr;
}
}
You have turned plain content into a centered responsive profile card. Next, you will give the theme button the click behavior its design promises.
Make the Theme Button Work
Your polished profile card already presents your learning goals in a responsive layout. Its theme button still cannot respond because visual styling does not define click behavior.
JavaScript supplies the missing interaction. The DOM lets your script find the controls that are already on the page.
In this step, get ready to:
- Store references to the page controls with document.querySelector().
- Toggle dark-theme when the theme button receives a click.
- Use the returned Boolean to synchronize the visible labels.
Connect the theme button
A click listener waits for a specific interaction before running its code. Your listener will toggle the existing dark theme class before updating the two visible text labels.
- Select app.js in the Visual Studio Code Explorer sidebar.
- Add the complete theme interaction by pasting this code into app.js:
const themeButton = document.querySelector(".theme-button");
const statusMessage = document.querySelector(".status");
themeButton.addEventListener("click", () => {
const darkThemeIsActive = document.body.classList.toggle("dark-theme");
if (darkThemeIsActive) {
themeButton.textContent = "Switch to light theme";
statusMessage.textContent = "Dark theme is active.";
} else {
themeButton.textContent = "Switch to dark theme";
statusMessage.textContent = "Light theme is active.";
}
});
How Does the Interaction Work?
- The two document.querySelector() calls store references to the theme button and status message.
- The addEventListener(type, listener) call runs the listener whenever the button receives a click.
- The toggle(token) call adds or removes the dark theme class. Its returned value records whether that class remains active.
- The darkThemeIsActive value chooses the matching button label and status message.
- Save app.js by pressing Ctrl+S.
Test both theme states
Before you test it, what do you expect the button label and status message to show after the first click?
- Switch back to Microsoft Edge from earlier.
- Refresh the local index.html page by pressing Ctrl+R.
- Click Switch to dark theme.
You should see the page switch to its dark colors. The button now reads Switch to light theme while the status reads Dark theme is active.
- Click Switch to light theme.
You should see the original light colors return. The button label and status message also return to their light theme text.
You did it. Your profile page now responds to every theme button click with coordinated colors and text.
Button Still Unresponsive?
Confirm that you saved app.js before refreshing the page. Unsaved JavaScript stays inside the editor.
Check that .theme-button and .status match the class names in index.html exactly.
Help me debug my theme button interaction.
✔️ Awesome, I've got everything!
Great. Double check that app.js is saved before you finish.
ⓧ I'd like to double check the full code
Your complete app.js should look exactly like this:
const themeButton = document.querySelector(".theme-button");
const statusMessage = document.querySelector(".status");
themeButton.addEventListener("click", () => {
const darkThemeIsActive = document.body.classList.toggle("dark-theme");
if (darkThemeIsActive) {
themeButton.textContent = "Switch to light theme";
statusMessage.textContent = "Dark theme is active.";
} else {
themeButton.textContent = "Switch to dark theme";
statusMessage.textContent = "Light theme is active.";
}
});
Your unchanged index.html should look exactly like this:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Tech Starter Page</title>
<link rel="stylesheet" href="style.css">
<script src="app.js" defer></script>
</head>
<body>
<main class="profile-card">
<header class="intro">
<p class="eyebrow">MY FIRST WEB PROJECT</p>
<h1>Hi, I’m Alex</h1>
<p class="bio">
I’m starting my journey in tech and building one small project at a time.
</p>
</header>
<section aria-labelledby="learning-title">
<h2 id="learning-title">What I’m learning</h2>
<div class="skills">
<article class="skill">
<h3>HTML</h3>
<p>Structures the content on a webpage.</p>
</article>
<article class="skill">
<h3>CSS</h3>
<p>Controls the page’s colors, spacing, and layout.</p>
</article>
<article class="skill">
<h3>JavaScript</h3>
<p>Adds behavior when someone interacts with the page.</p>
</article>
</div>
</section>
<button class="theme-button" type="button">Switch to dark theme</button>
<p class="status" aria-live="polite">Light theme is active.</p>
</main>
</body>
</html>
Your unchanged style.css should look exactly like this:
:root {
--page-background: #eef2ff;
--card-background: #ffffff;
--text-color: #172033;
--muted-text: #56627a;
--accent-color: #4f46e5;
--accent-hover: #3730a3;
--border-color: #d9def0;
--shadow-color: rgba(44, 52, 82, 0.16);
}
* {
box-sizing: border-box;
}
body {
min-height: 100vh;
margin: 0;
padding: 24px;
display: grid;
place-items: center;
font-family: "Segoe UI", Tahoma, sans-serif;
color: var(--text-color);
background: var(--page-background);
transition: color 200ms ease, background 200ms ease;
}
body.dark-theme {
--page-background: #111827;
--card-background: #1f2937;
--text-color: #f8fafc;
--muted-text: #cbd5e1;
--accent-color: #818cf8;
--accent-hover: #a5b4fc;
--border-color: #475569;
--shadow-color: rgba(0, 0, 0, 0.35);
}
.profile-card {
width: min(760px, 100%);
padding: 40px;
background: var(--card-background);
border: 1px solid var(--border-color);
border-radius: 24px;
box-shadow: 0 18px 50px var(--shadow-color);
}
.intro {
margin-bottom: 32px;
}
.eyebrow {
margin: 0 0 10px;
color: var(--accent-color);
font-size: 0.8rem;
font-weight: 700;
letter-spacing: 0.12em;
}
h1,
h2,
h3,
p {
margin-top: 0;
}
h1 {
margin-bottom: 12px;
font-size: clamp(2rem, 6vw, 3.5rem);
}
h2 {
margin-bottom: 16px;
}
.bio,
.skill p,
.status {
color: var(--muted-text);
line-height: 1.6;
}
.skills {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
margin-bottom: 28px;
}
.skill {
padding: 20px;
border: 1px solid var(--border-color);
border-radius: 16px;
}
.skill h3 {
margin-bottom: 8px;
}
.skill p {
margin-bottom: 0;
}
.theme-button {
padding: 12px 18px;
color: #ffffff;
background: var(--accent-color);
border: 0;
border-radius: 10px;
font: inherit;
font-weight: 700;
cursor: pointer;
}
.theme-button:hover {
background: var(--accent-hover);
}
.theme-button:focus-visible {
outline: 3px solid var(--accent-hover);
outline-offset: 3px;
}
.status {
margin: 12px 0 0;
font-size: 0.9rem;
}
@media (max-width: 640px) {
.profile-card {
padding: 26px;
}
.skills {
grid-template-columns: 1fr;
}
}
Secret mission
Track Your First Learned Skill
Extend your profile with a progress control for the HTML skill. Each click will change the card's appearance and update the button label to show whether you have learned it.
Clean Up Your Resources
Clean Up Your Resources
Everything you built lives inside the local tech-starter-page folder. There are no ongoing costs.
Choose whether to keep the project open, close it for later, or delete it entirely.
Resources you used:
- The local tech-starter-page folder containing index.html, style.css, and app.js.
Keep everything running
No action needed. Choose this if you want to keep testing the theme switcher or the learned-skill control.
- Leave the local index.html page open in Microsoft Edge.
- Keep Visual Studio Code open with the trusted tech-starter-page folder.
- Leave the tech-starter-page folder in its current location.
Pause - I'll come back to this later
Close the open tools to free up memory. Your project files remain ready for your next session.
- Close the local index.html tab in Microsoft Edge.
- Close Visual Studio Code.
- Reopen the tech-starter-page folder in Visual Studio Code when you want to continue.
- Press Ctrl + O in Microsoft Edge to reopen your page.
- Select index.html inside the tech-starter-page folder.
Delete - I don't want to use this again
Deleting tech-starter-page removes only this project folder.
- Close the local index.html tab in Microsoft Edge.
- Close Visual Studio Code.
- Return to the location where you created tech-starter-page in File Explorer.
- Select the tech-starter-page folder.
- Press the Delete key to move the folder to the Recycle Bin.
The project is now gone from its original location. Windows can still restore it from the Recycle Bin.
- Open the Recycle Bin.
- Select the tech-starter-page folder.
- Press the Delete key again to remove the selected folder permanently.
- Confirm the permanent deletion when Windows asks.
- Return to the folder's original location in File Explorer.
- Confirm that tech-starter-page no longer appears.
Nice Work!
Nice Work!
You did it! You built an interactive Tech Starter Profile Page that opens locally in Microsoft Edge.
You've learned how to:
- Build a valid three-file webpage. Use HTML for structure. Use CSS for presentation. Use JavaScript for behavior.
- Create a responsive profile card with clear visual hierarchy. Keep its skill cards readable in a narrow browser window.
- Turn the inactive theme button into a complete theme switcher. Use DOM selection to find each page element. Use a click event listener to toggle the dark-theme class. Update the visible text to reflect the active theme.
- Secret Mission: Add a skill-progress control to the HTML card. Toggle its learned state after each click. Update the card appearance. Update the button label.
Ready to quiz yourself?