Build a Developer Profile Card

Build a responsive profile card with HTML, CSS, and JavaScript interactions.

Introduction

30 Second Summary

A developer profile often has only a few seconds to make an introduction. On a narrow screen, a desktop-only layout can make that introduction difficult to read.

In this project, you will build a responsive developer profile card with three web technologies: HTML for structure, CSS for presentation, plus JavaScript for behavior. A theme button will switch its colors between light mode and dark mode.

What You'll Build

Your finished profile will open as a polished card in Microsoft Edge, ready to switch themes with a click.

By the end of this project, you'll have:

  • A polished developer profile that presents Alex Parker's introduction, three skill badges, plus an email link.
  • A working theme control that switches the page between light mode and dark mode. Its label updates immediately after every click.
  • A responsive layout that stays readable when the browser becomes narrow. The avatar moves above the text while the theme button fills the card width.
  • Secret Mission: Add a second button that reveals and hides a featured project panel.

Are there any prerequisites?

No prior coding experience is required. You already have Visual Studio Code, while the guide includes Microsoft Edge setup if the browser is missing.

Before We Start

Before the hands-on work begins, this step gives you a clear outcome to aim for. You are committing to build a responsive developer profile card that shows how HTML, CSS, and JavaScript work together.

Set Up the Project

A profile card needs a dependable workspace before you build visible features. This step removes setup friction before the first page takes shape.

You will verify Microsoft Edge. You will prepare the project in Visual Studio Code.

In this step, get ready to:
  • Verify Microsoft Edge opens on Windows.
  • Create the starter project workspace in Visual Studio Code.
  • Display the starter heading in Microsoft Edge.
Verify Microsoft Edge

Microsoft Edge renders the local page you build. Confirming the browser now gives every later visual check a reliable home.

  • Select Start on the Windows taskbar.

You'll see the Windows search field.

  • Type Microsoft Edge into the search field.

Check whether Microsoft Edge appears in the search results.

✔️ Microsoft Edge appears

  • Select Microsoft Edge from the search results.

You'll see a Microsoft Edge browser window. The browser is ready for your local profile page.

  • Leave Microsoft Edge open.

ⓧ Microsoft Edge is not installed

You'll see the installer appear in your browser's downloads.

  • Open the downloaded installer.

The device-change prompt is expected because the installer needs permission to add the browser.

  • Approve the device-change prompt.
  • Wait for the installation to finish.

You'll see Microsoft Edge open when the installation completes.

  • Leave Microsoft Edge open.

Microsoft Edge Won't Open?

  • Confirm the installer finished before searching for Microsoft Edge again.
  • Restart Windows if the installer completed but the browser still does not open.

Still stuck? Help me troubleshoot Microsoft Edge on Windows.

Create the project files

A dedicated workspace keeps every project file under one folder. Visual Studio Code shows that structure in its Explorer view.

  • Press the Windows key to open search.

You'll see the Windows search field.

  • Type Visual Studio Code into the search field.
  • Press Enter.

You'll see Visual Studio Code open.

What Is the Explorer View?

The Explorer view shows the files inside your open workspace. You will use its controls to create each part of the project.

  • Select File from the Visual Studio Code menu bar.
  • Select Open Folder....

You'll see the Windows folder picker.

  • Select Desktop in the folder picker.
  • Select New Folder.

You'll see a field for the new folder name.

  • Type developer-profile-card into the folder name field.
  • Press Enter.

You'll see the new `developer-profile-card` folder selected.

  • Select Select Folder.
  • Approve the workspace as trusted if Visual Studio Code asks.

You'll see developer-profile-card at the top of the Explorer view.

Why Separate Files?

HTML gives the page its structure.

CSS controls how that structure looks.

JavaScript adds behavior when someone interacts with the page.

  • Select New File... in the Explorer view.

You'll see a filename field beneath developer-profile-card.

  • Type index.html into the filename field.
  • Press Enter.

You'll see index.html in the Explorer view.

  • Select the developer-profile-card folder in the Explorer view.
  • Select New Folder.

You'll see a field for the folder name.

  • Type styles into the folder name field.
  • Press Enter.

You'll see the styles folder beneath developer-profile-card.

Your File Tree So Far

The project now has its main page plus a folder for presentation rules. This structure keeps each responsibility easy to find.

  • Select the styles folder in the Explorer view.
  • Select New File....

You'll see a filename field beneath the styles folder.

  • Type style.css into the filename field.
  • Press Enter.

You'll see style.css inside the styles folder.

  • Select the developer-profile-card folder in the Explorer view.
  • Select New Folder.

You'll see another field for a folder name.

  • Type scripts into the folder name field.
  • Press Enter.

You'll see the scripts folder beneath developer-profile-card.

One File Left

The final empty file gives the project a place for its future interaction code. Creating it now completes the starter structure.

  • Select the scripts folder in the Explorer view.
  • Select New File....

You'll see a filename field beneath the scripts folder.

  • Type main.js into the filename field.
  • Press Enter.

Your Explorer view now contains index.html, styles/style.css, and scripts/main.js.

Add the starter page

The starter document connects all three project files. Its heading provides a visible check that Microsoft Edge loaded the correct page.

  • Select index.html in the Explorer view.
  • Add the starter document by pasting this code:
<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Developer Profile Card</title>
    <link href="styles/style.css" rel="stylesheet" />
  </head>
  <body>
    <h1>My Developer Profile</h1>

    <script async src="scripts/main.js"></script>
  </body>
</html>

What Does This Document Set Up?

  • The <!doctype html> declaration tells Microsoft Edge to interpret the file as a modern HTML document.
  • The <title> element controls the browser tab text.
  • The <link> element connects styles/style.css to the page.
  • The <h1> element creates the visible starter heading.
  • The <script> element loads scripts/main.js.

✔️ Awesome, I've got everything!

Great. Double-check that the three files remain visible in the Explorer view.

ⓧ I'd like to double check the full code

Compare index.html with this complete starter document.

<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Developer Profile Card</title>
    <link href="styles/style.css" rel="stylesheet" />
  </head>
  <body>
    <h1>My Developer Profile</h1>

    <script async src="scripts/main.js"></script>
  </body>
</html>

The styles/style.css file should be completely empty.

The scripts/main.js file should be completely empty.

  • Save every open file by pressing Ctrl+K S.

Before you open the page, pause to predict what the browser tab and page will show.

  • Right-click index.html in the Visual Studio Code Explorer view.
  • Select Reveal in File Explorer.

You'll see File Explorer open with index.html selected.

  • Right-click index.html in File Explorer.
  • Select Open with.

You'll see a list of available applications.

  • Select Microsoft Edge.

You'll see Developer Profile Card on the browser tab. You'll see My Developer Profile as the page heading.

Your first visible page is working. Microsoft Edge is now reading the saved HTML from your project folder.

Don't See the Starter Heading?

  • Confirm index.html sits directly inside developer-profile-card.
  • Confirm the heading in index.html says My Developer Profile.
  • Save every open file before opening index.html again.

Still stuck? Help me find why my local HTML page is not displaying correctly.

Your editor, browser, and starter files are ready. Next, you'll turn the single heading into a complete profile structure.

Build the Profile Structure

Your starter page now opens locally in Microsoft Edge. That visible heading proves the browser can read your document.

Semantic HTML gives each part of the profile a clear purpose before presentation or behavior is added. This step replaces the placeholder with Alex Parker's complete profile content.

In this step, get ready to:
  • Build Alex Parker's profile header.
  • Add the About me section.
  • Complete the profile with a skills list plus an email link.
Build the profile header

The main element identifies the page's primary content. The profile header groups Alex Parker's identity at the top of that content.

  • Return to the index.html tab in Visual Studio Code.
  • Find the heading that contains My Developer Profile.
  • Delete the entire heading line.
  • Replace the deleted heading with the profile card structure by copying this code:
    <main class="profile-card">
      <button class="theme-button" id="theme-toggle" type="button">
        Switch to dark theme
      </button>

      <header class="profile-header">
        <div class="avatar">AP</div>
        <div>
          <p class="eyebrow">Frontend developer in training</p>
          <h1>Alex Parker</h1>
          <p class="tagline">I build clear, friendly experiences for the web.</p>
        </div>
      </header>

    </main>

What does this structure do?

  • The profile-card class gives the whole profile a shared styling hook.
  • The theme-toggle ID uniquely identifies the theme button.
  • The profile-header class groups the avatar with Alex Parker's introductory text.
  • Save index.html.
  • Switch back to Microsoft Edge.
  • Refresh the local page.

Good progress. Microsoft Edge now shows the theme button above Alex Parker's profile header.

The header includes the AP avatar plus the introductory text.

Profile header missing?

  • Confirm the new structure sits inside the document body.
  • Check that the closing main tag remains above the script line.
  • Save index.html before refreshing Microsoft Edge.

Still stuck? Help me find why my profile header is missing from index.html

Add the profile sections

Sections divide the profile into named topics. The first section explains what Alex is learning.

  • Return to index.html in Visual Studio Code.
  • Find the end of the profile header.
  • Place your cursor on the blank line below the profile header.
  • Add the About me section by copying this code:
      <section>
        <h2>About me</h2>
        <p>
          I am learning how HTML, CSS, and JavaScript work together to create
          useful interfaces.
        </p>
      </section>

What does this section do?

  • The section groups one topic within the profile.
  • The second-level heading names that topic as About me.
  • The paragraph gives visitors a short introduction to Alex's learning goal.
  • Save index.html.
  • Switch back to Microsoft Edge.
  • Refresh the local page.

You have given Alex's profile a clear purpose. Microsoft Edge now shows the About me heading with its introductory paragraph.

About me section missing?

  • Confirm the About me section sits below the profile header.
  • Check that every opening section tag has a matching closing tag.
  • Save the file before checking the browser again.

Need a hand? Help me fix the About me section in my profile HTML

An unordered list suits a collection where the sequence carries no special meaning. Each skill becomes its own list item.

  • Find the end of the About me section in index.html.
  • Place your cursor on the blank line below that section.
  • Add the Skills section by copying this code:
      <section>
        <h2>Skills I am learning</h2>
        <ul class="skill-list">
          <li>HTML</li>
          <li>CSS</li>
          <li>JavaScript</li>
        </ul>
      </section>

What does the skills list do?

  • The skill-list class gives the whole list a styling hook.
  • Each list item represents one skill.
  • The unordered list preserves meaningful page structure before visual badges are added.
  • Save index.html.
  • Switch back to Microsoft Edge.
  • Refresh the local page.

The profile is now easier to scan. Microsoft Edge shows a Skills I am learning heading above three skill items.

Skills list not showing correctly?

  • Confirm the Skills section sits below the About me section.
  • Check that all three list items sit inside the unordered list.
  • Compare the closing tags with the code block above.

Still stuck? Help me repair the skills list in index.html

Finish with the email link

A profile needs a clear contact action. The footer places that action after the profile information.

  • Find the end of the Skills section in index.html.
  • Place your cursor on the blank line below that section.
  • Add the profile footer by copying this code:
      <footer>
        <a class="contact-link" href="mailto:alex@example.com">Email me</a>
      </footer>

What does the footer do?

  • The footer holds the contact action at the end of the profile.
  • The contact-link class gives the email link a styling hook.
  • The link points to Alex Parker's example email address.
  • Save index.html.

Before you refresh, consider whether every profile detail now has a visible place.

  • Switch back to Microsoft Edge.
  • Refresh the local page.

Microsoft Edge shows Alex Parker's introduction above the About me section. The Skills section contains three items: HTML, CSS, JavaScript.

The Email me link appears below the skills. The Switch to dark theme button appears at the top in plain browser styling.

That completes the page structure. Every piece of Alex Parker's profile is now visible in the browser.

Complete profile not visible?

  • Confirm the About me section sits inside the profile card.
  • Confirm the Skills section sits inside the profile card.
  • Confirm the footer appears before the closing main tag.

Need help comparing the structure? Help me find the missing part of my profile page

  • Compare your saved index.html with the full file in the double-check tab if needed.

✔️ Awesome, I've got everything!

Your index.html now contains the complete semantic profile structure for this step.

ⓧ I'd like to double check the full code

<!doctype html>
<html lang="en-US">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>Developer Profile Card</title>
    <link href="styles/style.css" rel="stylesheet" />
  </head>
  <body>
    <main class="profile-card">
      <button class="theme-button" id="theme-toggle" type="button">
        Switch to dark theme
      </button>

      <header class="profile-header">
        <div class="avatar">AP</div>
        <div>
          <p class="eyebrow">Frontend developer in training</p>
          <h1>Alex Parker</h1>
          <p class="tagline">I build clear, friendly experiences for the web.</p>
        </div>
      </header>

      <section>
        <h2>About me</h2>
        <p>
          I am learning how HTML, CSS, and JavaScript work together to create
          useful interfaces.
        </p>
      </section>

      <section>
        <h2>Skills I am learning</h2>
        <ul class="skill-list">
          <li>HTML</li>
          <li>CSS</li>
          <li>JavaScript</li>
        </ul>
      </section>

      <footer>
        <a class="contact-link" href="mailto:alex@example.com">Email me</a>
      </footer>
    </main>

    <script async src="scripts/main.js"></script>
  </body>
</html>

This step changes only index.html. The styles/style.css file and scripts/main.js file remain empty.

Your profile now has meaningful content from top to bottom. Next, you'll turn this plain structure into a centered card with clear visual hierarchy.

Style the Card and Meet the Dead Button

Your semantic HTML profile now gives every piece of content a meaningful place. Microsoft Edge can display the full profile in plain browser styling.

In this step, CSS creates the visual hierarchy that turns the page into a profile card. At the end, you will test whether the polished theme button can change the page without JavaScript.

In this step, get ready to:
  • Create a centered profile card with spacing and color.
  • Use Flexbox to arrange the profile header and skill badges.
  • Test whether the styled theme button can change the page state.
Style the page and card

The box model controls the space around each element through padding, borders, and margins. These first rules create the full-page canvas before shaping the card inside it.

  • Select styles/style.css from the file list on the left side of Visual Studio Code.
  • Create the centered page canvas by adding this code:
* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  padding: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: Arial, sans-serif;
  color: #1f2937;
  background-color: #eef2ff;
}

What does this code do?

  • The universal selector makes declared widths include each element's padding and border.
  • The body fills the viewport and uses Flexbox to center its content.
  • The remaining declarations establish the page spacing, typeface, text color, and pale background.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the local index.html page.

You will see the profile content centered against a pale purple background.

Is the page still aligned to the top?

  • Confirm that the body rule includes both centering declarations.
  • Check that you saved styles/style.css before refreshing Microsoft Edge.

Still stuck? Help me troubleshoot why my CSS is not centering the profile content.

  • Shape the profile card by adding this code below the body rule:
.profile-card {
  width: 90%;
  max-width: 680px;
  padding: 32px;
  background-color: white;
  border: 2px solid #c7d2fe;
  border-radius: 24px;
}

How does the card take shape?

  • The percentage width leaves space around the card on smaller windows.
  • The maximum width prevents the card from stretching too far on a wide screen.
  • Padding creates room inside the border while the corner radius softens the card outline.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see the profile content inside a white card with a light border and rounded corners.

Do you still see bare text?

  • Confirm that the selector starts with .profile-card.
  • Check that index.html still contains class="profile-card" on the main element.

Still stuck? Help me find why the profile card CSS is not appearing.

Build the visual hierarchy

Flexbox arranges items along one direction while keeping their alignment predictable. You will use it for the profile header and the wrapping row of skill badges.

  • Style the theme button by adding this code below the .profile-card rule:
.theme-button {
  display: block;
  margin: 0 0 24px auto;
  padding: 10px 16px;
  font-family: Arial, sans-serif;
  color: white;
  background-color: #4338ca;
  border: 2px solid #4338ca;
  border-radius: 30px;
}

How does the button styling work?

  • The automatic left margin positions the button against the right side of the card.
  • Padding gives the label room inside the button.
  • Matching border and background colors create a solid purple control.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see a purple pill-shaped theme button aligned to the right side of the card.

Does the button still look plain?

  • Confirm that the selector is spelled .theme-button.
  • Check that the button in index.html still uses the same class name.

Still stuck? Help me troubleshoot why the theme button CSS is not appearing.

  • Arrange the profile header by adding this code below the .theme-button rule:
.profile-header {
  display: flex;
  align-items: center;
  margin-bottom: 28px;
}

What happens to the header?

  • Flexbox places the avatar beside the profile text.
  • Center alignment keeps both parts level across the row.
  • The bottom margin separates the header from the About me section.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see the AP text move beside Alex Parker's profile information.

Is the header still stacked?

  • Confirm that display: flex is inside the .profile-header rule.
  • Check that the header in index.html still uses class="profile-header".

Still stuck? Help me fix the profile header alignment.

  • Turn the initials into an avatar by adding this code below the .profile-header rule:
.avatar {
  width: 96px;
  height: 96px;
  margin-right: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 96px;
  font-size: 28px;
  color: white;
  background-color: #4338ca;
  border-radius: 50%;
}

How does the avatar become circular?

  • Equal width and height create a square base for the avatar.
  • The percentage corner radius turns that square into a circle.
  • The inner Flexbox centers the AP initials inside the circle.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see a purple circular avatar with white AP initials beside the profile text.

Is the avatar the wrong shape?

  • Confirm that the width and height are both 96px.
  • Check that border-radius uses 50%.

Still stuck? Help me troubleshoot the avatar size and shape.

  • Create clearer text hierarchy by adding these rules below the .avatar rule:
.eyebrow {
  margin: 0 0 6px;
  color: #4338ca;
}

h1 {
  margin: 0;
  font-size: 36px;
}

h2 {
  margin: 28px 0 10px;
  font-size: 20px;
}

p {
  line-height: 1.6;
}

.tagline {
  margin: 8px 0 0;
}

How does the text hierarchy improve?

  • The eyebrow color connects the role label to the purple accent color.
  • The heading sizes make the developer's name the strongest text on the card.
  • Paragraph line height and targeted margins create readable spacing without changing the HTML.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see a larger Alex Parker heading with clearer spacing between the role, tagline, and profile sections.

Does the text spacing look uneven?

  • Check that each selector has its own opening and closing brace.
  • Confirm that the h1 and h2 rules use the matching font sizes from the code block.

Still stuck? Help me find a syntax problem in my profile typography CSS.

  • Arrange the skills as a wrapping row by adding this code below the .tagline rule:
.skill-list {
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}

Why does the skill list wrap?

  • Removing the default margin and padding clears the browser's list spacing.
  • Flexbox places the skills in a row.
  • Wrapping allows later badges to move onto another line when space runs out.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see HTML, CSS, and JavaScript arranged in one row without bullet markers.

Do the skills still have bullets?

  • Confirm that list-style: none appears inside the .skill-list rule.
  • Check that the unordered list in index.html still uses class="skill-list".

Still stuck? Help me troubleshoot the skill list layout.

  • Turn each skill into a badge by adding this code below the .skill-list rule:
.skill-list li {
  margin: 0 8px 8px 0;
  padding: 8px 12px;
  color: #312e81;
  background-color: #e0e7ff;
  border-radius: 30px;
}

How do the badges work?

  • Padding gives each skill label space inside its colored background.
  • Margins keep neighboring badges from touching.
  • The corner radius creates the rounded badge shape.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see three pale purple skill badges with rounded ends.

Are the skills still plain text?

  • Confirm that the selector includes both .skill-list and li.
  • Check that the background color declaration sits inside the badge rule.

Still stuck? Help me troubleshoot why the skill badges are not styled.

  • Style the email action by adding this code below the .skill-list li rule:
.contact-link {
  display: inline-block;
  margin-top: 20px;
  padding: 10px 16px;
  color: white;
  background-color: #4338ca;
  border-radius: 30px;
}

Why style the email link this way?

  • Inline-block layout allows padding to shape the link like a button.
  • The top margin separates the contact action from the skills section.
  • The shared purple color keeps the theme and contact controls visually connected.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see the Email me link as a purple rounded contact action below the skills.

Does the email link still look ordinary?

  • Confirm that the selector is spelled .contact-link.
  • Check that the email link in index.html still carries the matching class.

Still stuck? Help me troubleshoot the contact link styling.

Prepare the dark theme for a button test

A theme needs a coordinated palette for the page and its nested elements. These selectors define the alternate colors under the body.dark-theme state.

  • Add the dark-theme color rules below the .contact-link rule:
body.dark-theme {
  color: #e5e7eb;
  background-color: #111827;
}

body.dark-theme .profile-card {
  background-color: #1f2937;
  border-color: #6366f1;
}

body.dark-theme .eyebrow {
  color: #c4b5fd;
}

body.dark-theme .skill-list li {
  color: #e0e7ff;
  background-color: #3730a3;
}

body.dark-theme .contact-link {
  color: #1f2937;
  background-color: #c4b5fd;
}

How is the alternate palette organized?

  • The first rule defines the dark page background and light text.
  • The nested selectors adjust the card border, eyebrow, skill badges, and contact link.
  • Grouping the colors under one page state keeps the alternate theme coordinated.
  • Save styles/style.css.
  • Switch back to Microsoft Edge.
  • Refresh the page.

You will see a centered white card with a circular AP avatar, a horizontal profile header, rounded skill badges, and two purple controls.

Before you test the theme button, do you think its finished appearance is enough to change the page colors?

  • Click Switch to dark theme.

The card stays in its light colors. The button label also stays the same.

That is the intended shortfall. CSS defines how each state looks. The empty scripts/main.js file contains no click behavior to move between them.

Does your result look different?

  • Confirm that scripts/main.js is still empty if the button changes the page.
  • Check that every CSS rule is saved if the profile still looks unstyled.
  • Confirm that index.html still links to styles/style.css.

Still stuck? Help me compare my styled profile and dead theme button with the expected result.

✔️ Awesome, I've got everything!

Your CSS matches the finished styling for this step.

ⓧ I'd like to double check the full code

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  padding: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: Arial, sans-serif;
  color: #1f2937;
  background-color: #eef2ff;
}

.profile-card {
  width: 90%;
  max-width: 680px;
  padding: 32px;
  background-color: white;
  border: 2px solid #c7d2fe;
  border-radius: 24px;
}

.theme-button {
  display: block;
  margin: 0 0 24px auto;
  padding: 10px 16px;
  font-family: Arial, sans-serif;
  color: white;
  background-color: #4338ca;
  border: 2px solid #4338ca;
  border-radius: 30px;
}

.profile-header {
  display: flex;
  align-items: center;
  margin-bottom: 28px;
}

.avatar {
  width: 96px;
  height: 96px;
  margin-right: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 96px;
  font-size: 28px;
  color: white;
  background-color: #4338ca;
  border-radius: 50%;
}

.eyebrow {
  margin: 0 0 6px;
  color: #4338ca;
}

h1 {
  margin: 0;
  font-size: 36px;
}

h2 {
  margin: 28px 0 10px;
  font-size: 20px;
}

p {
  line-height: 1.6;
}

.tagline {
  margin: 8px 0 0;
}

.skill-list {
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}

.skill-list li {
  margin: 0 8px 8px 0;
  padding: 8px 12px;
  color: #312e81;
  background-color: #e0e7ff;
  border-radius: 30px;
}

.contact-link {
  display: inline-block;
  margin-top: 20px;
  padding: 10px 16px;
  color: white;
  background-color: #4338ca;
  border-radius: 30px;
}

body.dark-theme {
  color: #e5e7eb;
  background-color: #111827;
}

body.dark-theme .profile-card {
  background-color: #1f2937;
  border-color: #6366f1;
}

body.dark-theme .eyebrow {
  color: #c4b5fd;
}

body.dark-theme .skill-list li {
  color: #e0e7ff;
  background-color: #3730a3;
}

body.dark-theme .contact-link {
  color: #1f2937;
  background-color: #c4b5fd;
}

Your profile now looks like a finished card with a clear identity row and skill badges. Next, you will give the polished theme button the JavaScript behavior its appearance promises.

Make the Theme Button Work

The styled card now looks ready for interaction in Microsoft Edge. The theme button still ignores every click.

CSS already contains the dark colors. JavaScript gives the button behavior through a click event. The handler will change the page state before synchronizing the visible label.

In this step, get ready to:
  • Select the theme button from the page.
  • Register a click listener that toggles the dark-theme class.
  • Synchronize the button label with the active theme.
Match the button to the page

The DOM is the browser's live map of the elements in your HTML. document.querySelector() can use a CSS selector to find the theme button in that map.

  • In the Explorer sidebar from earlier, select index.html.
  • Locate the button whose id is theme-toggle.
  • Switch to styles/style.css in the Explorer sidebar.
  • Locate the body.dark-theme rules.

The button ID gives JavaScript its target. The CSS class already holds the visual theme change.

Add the click handler

An event listener waits for a specific action on an element. This listener uses classList.toggle() to add or remove the existing dark-theme class after each click.

  • Select scripts/main.js in the Explorer sidebar.
  • Connect the button to the dark theme by pasting this code into the empty editor:
const themeButton = document.querySelector("#theme-toggle");

themeButton.addEventListener("click", () => {
  const darkThemeIsOn = document.body.classList.toggle("dark-theme");
});

What does this code do?

  • document.querySelector("#theme-toggle") finds the button through its unique ID. The themeButton variable stores that reference.
  • addEventListener("click", ...) runs the callback whenever the visitor activates the button.
  • classList.toggle("dark-theme") switches the class on document.body. The result is stored in darkThemeIsOn.
  • Save scripts/main.js.

Before you test it, predict whether the card colors should change after one click.

  • Switch back to Microsoft Edge.
  • Refresh index.html.
  • Click Switch to dark theme once.

You'll see the page use its dark colors. The button label still reads Switch to dark theme.

The page now reacts to your click. The unchanged label gives you the next job.

Button still doing nothing?

  • Confirm that you saved scripts/main.js before refreshing Microsoft Edge.
  • Check that #theme-toggle includes the leading hash symbol in document.querySelector().
  • Check that scripts/main.js matches the script path in index.html.

If the button remains unresponsive, help me debug the theme button click listener.

Synchronize the button label

A boolean records one of two states. Here, darkThemeIsOn reports whether the class remains on the page after the toggle.

The handler can use that result to choose the correct label. Setting textContent updates the words inside the button immediately.

  • Switch back to scripts/main.js.
  • Place your cursor on the blank line immediately after the darkThemeIsOn declaration.
  • Add this decision block:
  if (darkThemeIsOn) {
    themeButton.textContent = "Switch to light theme";
  } else {
    themeButton.textContent = "Switch to dark theme";
  }

How does the label stay synchronized?

  • The if branch runs when darkThemeIsOn is true. It changes the label to Switch to light theme.
  • The else branch runs when the dark-theme class has been removed. It restores the label to Switch to dark theme.
  • Save scripts/main.js.

Before you test both directions, predict which label should appear after the first click.

  • Switch back to Microsoft Edge.
  • Refresh index.html.
  • Click Switch to dark theme once.

You'll see the dark colors. The button label now reads Switch to light theme.

Before the next click, predict which theme should return. Predict which label should return.

  • Click Switch to light theme once.

You'll see the original light colors return. The button label changes back to Switch to dark theme.

Theme changes but the label does not?

  • Check that the if block sits inside the click listener after the darkThemeIsOn declaration.
  • Confirm that every use of darkThemeIsOn has the same capitalization.
  • Compare the opening braces with the closing braces in scripts/main.js.

If the label remains out of sync, help me check the boolean and textContent logic.

✔️ Awesome, I've got everything!

Your saved scripts/main.js now toggles the theme class. Its button label follows the active theme.

ⓧ I'd like to double check the full code

const themeButton = document.querySelector("#theme-toggle");

themeButton.addEventListener("click", () => {
  const darkThemeIsOn = document.body.classList.toggle("dark-theme");

  if (darkThemeIsOn) {
    themeButton.textContent = "Switch to light theme";
  } else {
    themeButton.textContent = "Switch to dark theme";
  }
});

You made the theme control fully interactive. Next, you'll adapt the same card to narrow browser widths.

Make the Layout Responsive

Your theme control now changes the profile card between light and dark colors. The layout still assumes that the browser has plenty of horizontal room.

At narrow widths, the avatar competes with the profile text for the same row. A CSS media query can rearrange that content when the viewport reaches 600px or less.

In this step, get ready to:
  • Observe where the desktop header becomes cramped.
  • Add responsive styles for viewports of 600px or less.
  • Verify every width-theme combination.
Expose the cramped desktop layout

The current .profile-header uses Flexbox to keep the avatar beside the text. Shrinking the browser lets you see when that row loses breathing room.

Before you narrow the window, where do you think the fixed 96px avatar puts the most pressure?

  • Switch back to Microsoft Edge.
  • Click Switch to light theme if dark colors are active.
  • Drag the right edge of the browser window inward until the card becomes much narrower.

You'll see the avatar stay beside the text as the available space shrinks. The header starts to feel cramped.

The theme button also keeps its content width while the card closes in around it.

Add the responsive media query

A media query applies nested CSS rules only when a viewport condition matches. The max-width condition lets the existing desktop rules remain in charge above the breakpoint.

  • Return to styles/style.css in Visual Studio Code.
  • Scroll to the closing brace of the final body.dark-theme .contact-link rule.
  • Add the media query after that brace by pasting this code:
@media (max-width: 600px) {
  body {
    padding: 16px;
  }

  .profile-card {
    width: 100%;
    padding: 24px;
  }

  .theme-button {
    width: 100%;
    margin-left: 0;
  }

  .profile-header {
    flex-direction: column;
    text-align: center;
  }

  .avatar {
    margin: 0 0 16px;
  }
}

How does the breakpoint work?

  • The @media (max-width: 600px) condition activates its nested rules at the breakpoint.
  • The body rule reduces the space around the card.
  • The .profile-card rule uses the available width with smaller inner spacing.
  • The .theme-button rule stretches the control across the card.
  • The .profile-header rule changes the Flexbox direction to a centered column.
  • The .avatar rule replaces the desktop right margin with bottom spacing.

Before you check the page, which desktop element do you expect to move first when the breakpoint activates?

  • Save styles/style.css.
  • Return to Microsoft Edge.
  • Refresh the profile page.
  • Narrow the browser window until the header changes.

You'll see the avatar move above the profile text. The button stretches across the card.

The card also gains smaller outer spacing. These changes show that the media query is active.

Media query not activating?

  • Confirm the @media (max-width: 600px) block sits below the final dark-theme rule in styles/style.css.
  • Check that every selector inside the media query has matching opening and closing braces.

Still stuck? Help me find why my responsive CSS media query is not activating.

✔️ Awesome, I've got everything!

Your saved stylesheet now contains the responsive rules.

ⓧ I'd like to double check the full code

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  padding: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: Arial, sans-serif;
  color: #1f2937;
  background-color: #eef2ff;
}

.profile-card {
  width: 90%;
  max-width: 680px;
  padding: 32px;
  background-color: white;
  border: 2px solid #c7d2fe;
  border-radius: 24px;
}

.theme-button {
  display: block;
  margin: 0 0 24px auto;
  padding: 10px 16px;
  font-family: Arial, sans-serif;
  color: white;
  background-color: #4338ca;
  border: 2px solid #4338ca;
  border-radius: 30px;
}

.profile-header {
  display: flex;
  align-items: center;
  margin-bottom: 28px;
}

.avatar {
  width: 96px;
  height: 96px;
  margin-right: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 96px;
  font-size: 28px;
  color: white;
  background-color: #4338ca;
  border-radius: 50%;
}

.eyebrow {
  margin: 0 0 6px;
  color: #4338ca;
}

h1 {
  margin: 0;
  font-size: 36px;
}

h2 {
  margin: 28px 0 10px;
  font-size: 20px;
}

p {
  line-height: 1.6;
}

.tagline {
  margin: 8px 0 0;
}

.skill-list {
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  list-style: none;
}

.skill-list li {
  margin: 0 8px 8px 0;
  padding: 8px 12px;
  color: #312e81;
  background-color: #e0e7ff;
  border-radius: 30px;
}

.contact-link {
  display: inline-block;
  margin-top: 20px;
  padding: 10px 16px;
  color: white;
  background-color: #4338ca;
  border-radius: 30px;
}

body.dark-theme {
  color: #e5e7eb;
  background-color: #111827;
}

body.dark-theme .profile-card {
  background-color: #1f2937;
  border-color: #6366f1;
}

body.dark-theme .eyebrow {
  color: #c4b5fd;
}

body.dark-theme .skill-list li {
  color: #e0e7ff;
  background-color: #3730a3;
}

body.dark-theme .contact-link {
  color: #1f2937;
  background-color: #c4b5fd;
}

@media (max-width: 600px) {
  body {
    padding: 16px;
  }

  .profile-card {
    width: 100%;
    padding: 24px;
  }

  .theme-button {
    width: 100%;
    margin-left: 0;
  }

  .profile-header {
    flex-direction: column;
    text-align: center;
  }

  .avatar {
    margin: 0 0 16px;
  }
}

What should match?

The final @media (max-width: 600px) block is the only addition to styles/style.css. Everything above it remains unchanged.

Test every layout combination

A responsive layout needs checks on both sides of its breakpoint. Testing both themes confirms that the existing interaction still works after the CSS rearranges the card.

Before you run the full check, do you expect the theme button to keep working after the layout changes?

  • Click Switch to dark theme while the browser is narrow.

You'll see the dark colors across the narrow card. The button label changes to Switch to light theme.

  • Drag the right edge of the browser outward until the avatar sits beside the profile text.

You'll see the desktop header return to a row. The dark theme remains active.

  • Click Switch to light theme at the wide browser width.

You'll see the light colors return across the wide card. The button label changes to Switch to dark theme.

  • Drag the right edge of the browser inward until the avatar moves above the profile text.

You'll see the avatar above the profile text. The profile text is centered.

The theme button fills the card width. The card uses smaller spacing.

  • Scan the bottom edge of the page for a horizontal scrollbar.

You should not see a horizontal scrollbar. The complete card remains readable at 600px or less.

You've finished the core build. Your profile card now stays readable in both themes at narrow widths.

Secret mission

Add a Project Reveal

Your theme button already changes one part of the page. This challenge asks you to reuse that interaction pattern for a featured-project panel with its own synchronized label.

Clean Up Your Resources

Clean Up Your Resources

Your profile card runs entirely on your computer, so there are no ongoing costs. Decide whether to keep the project available, pause your work, or delete the local files.

Resources you used:

  • The local developer-profile-card folder containing index.html, styles/style.css, and scripts/main.js.

Keep everything running

No action needed. Choose this if you want to keep editing or demonstrating your profile card.

  • Keep the developer-profile-card folder in its current location.
  • Keep index.html available as the page you open for future demonstrations.
  • Return to the project in Visual Studio Code whenever you want to practise more HTML, CSS, or JavaScript.

Pause - I'll come back to this later

Close your project tools to clear your workspace while keeping every file available for later.

  • Close the profile card tab in Microsoft Edge.
  • Close Visual Studio Code.
  • Leave the developer-profile-card folder in its current location.

Delete - I don't want to use this again

Deleting the folder removes your complete profile card from your computer. Visual Studio Code and Microsoft Edge remain installed.

  • Close the profile card tab in Microsoft Edge.
  • Close Visual Studio Code.
  • Return to the location where you created developer-profile-card using your computer's folder browser.
  • Delete the developer-profile-card folder.
  • Empty your computer's deleted-items folder to remove the project files completely.
  • Check the original location to confirm that developer-profile-card is gone.

Nice Work!

Nice Work!

You did it! Your responsive developer profile card now adapts to narrow screens. Its theme control and featured-project control update the page immediately.

You've learned how to:

  • Build a profile with semantic HTML. Organize the content with headings, sections, a skills list, and a contact link.
  • Style a polished card with the CSS box model. Arrange the profile header and skill badges with Flexbox. Adapt the layout for narrow screens with a responsive media query.
  • Connect a native button to JavaScript with DOM selection. Respond to click events with class toggling. Keep the theme button label synchronized with the page state.
  • Secret Mission: Reveal and hide a featured-project panel with an independently controlled button.

Ready to quiz yourself?