Build an Interactive Profile Card

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

Introduction

30 Second Summary

Introducing yourself online can feel flat when your words sit on a blank page. A little structure and interaction can turn that introduction into something people remember.

In this project, you will build a personal profile card in MDN Playground using HTML, CSS, and JavaScript. You will watch it grow from plain content into a styled interface that responds when its button is clicked.

What You'll Build

You click a polished profile card's button to reveal an updated learning message in the browser.

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

  • A personal profile card that displays your name and introduces your learning journey.
  • A polished interface with centered content, clear spacing, rounded corners, and visible button states.
  • An interactive button that changes the card's message and updates its own label when clicked.
  • Secret Mission: Add a light and dark theme switch that updates the card's colors and button label.

Are There Any Prerequisites?

You only need a Mac, a web browser, and internet access. No previous coding experience or software installation is required.

Before We Start

Your profile card begins with a clear purpose. Before any hands-on work, lock in who it represents and why you want to build it.

Open Your Browser Workspace

A first coding session can lose momentum when it begins with software installation. A browser-based editor takes you straight to a visible result.

In this step, you'll open MDN Playground in your browser. You'll identify where HTML, CSS, JavaScript, and the preview fit together.

In this step, get ready to:
  • Open MDN Playground in your browser.
  • Identify the HTML, CSS, JAVASCRIPT, and preview areas.
  • Enter a test heading that appears in the preview.
Open MDN Playground

MDN Playground keeps each language in its own editor area. The preview combines their output into one browser result.

  • In your existing browser, open the official MDN Playground.
  • Locate the HTML, CSS, JAVASCRIPT, and preview areas.

You'll see separate editor areas for HTML, CSS, and JAVASCRIPT. You'll also see a preview area for the combined result.

How does the workspace fit together?

  • The HTML panel holds the page structure.
  • The CSS panel controls the page appearance.
  • The JAVASCRIPT panel adds behavior to the page.
  • The preview area combines all three parts into the result you can see.

This browser workflow skips software installation. Your first piece of code can appear on screen immediately.

Can't see the workspace?

  • Check that your browser is connected to the internet.
  • Confirm that the address bar contains https://developer.mozilla.org/en-US/play.
  • Refresh the page if the editor areas do not finish loading.

Help me load the MDN Playground workspace.

Add a test heading

HTML gives a page its structure. An <h1> element marks the page's main heading.

  • Click inside the HTML panel.
  • Select all existing content by pressing Cmd+A (macOS) or Ctrl+A (Windows).

The existing HTML should now be highlighted.

  • Remove the highlighted content by pressing Delete (macOS) or Backspace (Windows).

The HTML panel is now empty and ready for your test code.

Before you add the code, which result do you expect: ordinary body text or a page heading? Hold your answer in mind.

  • Add the test heading to the HTML panel by entering this code:
<h1>Hello, tech!</h1>

What does this code do?

  • The <h1> and </h1> tags mark the content as the page's main heading.
  • The browser displays Hello, tech! as the heading text.
  • Check the preview after the code appears in the HTML panel.

You'll see a large “Hello, tech!” heading in the preview. Your browser is now rendering the HTML you entered.

Heading missing from the preview?

  • Confirm that you entered the code in the HTML panel.
  • Check that <h1> appears before the heading text.
  • Check that </h1> appears after the heading text.

Help me fix my HTML heading.

✔️ Awesome, I've got everything!

Your HTML panel contains the test heading. The preview proves that your browser is rendering it.

ⓧ I'd like to double check the full code

The complete index.html checkpoint contains one heading.

<h1>Hello, tech!</h1>

That's your first visible coding win: your HTML now controls what appears in the preview. Next, you'll replace the test heading with the structure of your profile card.

Build the Card Structure

Your MDN Playground workspace is ready. Its preview already proves the browser can render your test HTML heading.

A profile card needs meaningful structure before styling can improve it. The preview gives you a visible profile as soon as that structure is in place.

In this step, get ready to:
  • Replace the test heading with the profile card structure.
  • Personalize the name displayed on the card.
  • Personalize the opening message while preserving its code hooks.
Replace the test heading

Each HTML element gives one piece of content a clear role. The class names and IDs become stable hooks for later steps.

  • In the HTML panel from earlier, select the entire <h1>Hello, tech!</h1> line.
  • Replace that line with this profile structure:
<main class="profile-card">
  <p class="eyebrow">MY FIRST WEB PROJECT</p>
  <h1>Hi, I'm Sam.</h1>
  <p id="learning-message">I'm starting my tech journey.</p>
  <button id="learning-button" type="button">Show what I'm learning</button>
</main>

What does this HTML do?

  • The <main class="profile-card"> element groups the entire card into one section.
  • The eyebrow class identifies the small label above your name.
  • The profile-card and eyebrow class values give CSS stable styling hooks.
  • The learning-message and learning-button IDs give JavaScript exact elements to select.
  • The type="button" attribute identifies this element as a button with no default action.
  • Pause after your edit to let MDN Playground refresh the preview.
  • Check the preview panel.

You'll see MY FIRST WEB PROJECT above Hi, I'm Sam..

The learning message appears above the Show what I'm learning button.

You have the first complete card structure on screen. Every visible part now has a clear HTML role.

Card Missing From the Preview?

  • Confirm that you replaced the old heading instead of pasting the card inside it.
  • Check that every opening tag has a matching closing tag.
  • Compare each class name and ID with the reference code.

Help me find the problem in my profile card HTML.

Personalize the card text

HTML tags define the structure. The words between those tags are the content you can personalize safely.

  • In the HTML panel, find the line containing Hi, I'm Sam..
  • Replace only Sam with your name.
  • Find the line containing I'm starting my tech journey..
  • Replace only that sentence with a short message about what you are learning.
  • Keep profile-card, eyebrow, learning-message, and learning-button unchanged.

Before you check, predict which words the preview will show from your edits.

  • Check the preview panel.

You'll see the eyebrow label above your name. You'll also see your learning message above the Show what I'm learning button.

You've turned the test heading into a profile someone can read at a glance.

Personal Text Not Showing?

  • Check that your personalized text still sits between its opening and closing tags.
  • Restore any missing angle brackets by comparing your HTML with the reference below.
  • Confirm that you edited the HTML panel.

Help me fix my personalized profile text.

✔️ Awesome, I've got everything!

Great. Your preview now shows the complete card structure with your name and learning message.

ⓧ I'd like to double check the full code

Use this canonical version to compare the tags and code hooks. Your displayed name and learning message can contain your own text.

<main class="profile-card">
  <p class="eyebrow">MY FIRST WEB PROJECT</p>
  <h1>Hi, I'm Sam.</h1>
  <p id="learning-message">I'm starting my tech journey.</p>
  <button id="learning-button" type="button">Show what I'm learning</button>
</main>

Your profile now has a clear structure that the browser can display. Next, you'll use CSS to turn this plain content into a centered profile card.

Style the Profile Card

Your profile content now appears in the preview. Its default browser layout makes the information harder to present as a finished card.

In this step, you'll use CSS to center the layout. You'll shape every element into a polished profile card.

In this step, get ready to:
  • Center the page content inside the preview.
  • Style the card text and controls.
  • Test how the styled button responds to a click.
Center the page and shape the card

CSS controls how your existing HTML appears in the browser. The first rules create a full-height canvas for the card.

  • Switch back to the CSS panel in MDN Playground.
  • Add the page-wide layout rules by entering this code:
* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  font-family: system-ui, sans-serif;
  color: #172554;
  background: #eef2ff;
}

What do these rules do?

  • The universal selector makes element sizing more predictable.
  • The body uses a grid to place the content in the center of the preview.
  • The minimum height lets the body fill the browser preview.
  • The padding keeps the content away from the preview edges.
  • Look at the preview.

Good start. Your content is now centered on a soft blue background.

Is the content still in the corner?

Check that you entered the rules in the CSS panel. Confirm that every opening brace has a matching closing brace.

Ask for help with the page layout.

The page is centered, but the content still sits directly on the background. A dedicated card surface gives the profile a clear boundary.

  • Add the card rules below the body rules by entering this code:
.profile-card {
  width: 100%;
  max-width: 420px;
  padding: 32px;
  text-align: center;
  background: #ffffff;
  border-radius: 24px;
  box-shadow: 0 20px 50px rgba(30, 64, 175, 0.18);
}

How does the card take shape?

  • The width lets the card use the available space.
  • The maximum width stops the card from becoming too wide.
  • The padding creates space between the content and the card edges.
  • The rounded corners and shadow lift the white card from the background.
  • Check the preview again.

The centered content now sits inside a white card with rounded corners. Its shadow separates the card from the page.

Does the card still look flat?

Confirm that the selector begins with .profile-card. The class must match the value in class="profile-card".

Ask for help with the card styles.

Style the text and button

Visual hierarchy helps someone scan your profile in order. The eyebrow label needs a smaller style that separates it from your name.

  • Add the eyebrow rules below the card rules by entering this code:
.eyebrow {
  margin: 0 0 12px;
  color: #4f46e5;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
}

Why style the eyebrow separately?

  • The smaller font size keeps the label below the main heading in the visual hierarchy.
  • The heavier weight helps the uppercase letters remain readable.
  • The letter spacing gives the short label room to breathe.
  • Inspect the eyebrow label in the preview.

The label now appears small and purple above your name. Its wider letter spacing gives it a distinct role.

Is the eyebrow unchanged?

Confirm that the selector is .eyebrow. Check that the HTML still contains class="eyebrow".

Ask for help with the eyebrow styles.

The name needs more visual weight. The learning message needs enough space to remain balanced when its text changes later.

  • Add the heading and message rules below the eyebrow rules by entering this code:
h1 {
  margin: 0 0 12px;
  font-size: 2.4rem;
}

#learning-message {
  min-height: 3rem;
  margin: 0 0 20px;
  line-height: 1.5;
}

How do these rules improve the text?

  • The heading size makes your name the card's main focal point.
  • The heading margin creates space before the learning message.
  • The message minimum height reserves room for a longer update.
  • The line height keeps the message readable if it wraps onto another line.
  • Compare the heading and message in the preview.

Your name now stands out as the main heading. The learning message has more space beneath it.

Is the message spacing missing?

Confirm that the selector includes the # before learning-message. That symbol targets the matching HTML ID.

Ask for help with the text styles.

The final styling turns the basic control into a clear action. Separate hover and focus states show when someone is interacting with it.

  • Add the button rules below the message rules by entering this code:
button {
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff;
  background: #4f46e5;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

button:hover,
button:focus-visible {
  background: #3730a3;
}

How does the button signal interaction?

  • The padding creates a larger control that is easier to select.
  • The large border radius produces the pill shape.
  • The inherited font keeps the button consistent with the rest of the card.
  • The interaction states use a darker background when the button is hovered or focused.
  • Move your pointer over the learning button.

The button becomes darker while your pointer is over it.

  • Press Tab until the learning button receives focus.

The darker focus state confirms that the button responds to keyboard navigation too. Your card's visual styling is complete.

Are the button states missing?

Confirm that the hover and focus rules appear after the main button rule. Check that both selectors share the same declaration block.

Ask for help with the button states.

✔️ Awesome, I've got everything!

Your CSS is in place. The preview should show a centered white card with styled text and a purple button.

ⓧ I'd like to double check the full code

Here is the complete index.html for comparison:

<main class="profile-card">
  <p class="eyebrow">MY FIRST WEB PROJECT</p>
  <h1>Hi, I'm Sam.</h1>
  <p id="learning-message">I'm starting my tech journey.</p>
  <button id="learning-button" type="button">Show what I'm learning</button>
</main>

Here is the complete styles.css for comparison:

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  font-family: system-ui, sans-serif;
  color: #172554;
  background: #eef2ff;
}

.profile-card {
  width: 100%;
  max-width: 420px;
  padding: 32px;
  text-align: center;
  background: #ffffff;
  border-radius: 24px;
  box-shadow: 0 20px 50px rgba(30, 64, 175, 0.18);
}

.eyebrow {
  margin: 0 0 12px;
  color: #4f46e5;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
}

h1 {
  margin: 0 0 12px;
  font-size: 2.4rem;
}

#learning-message {
  min-height: 3rem;
  margin: 0 0 20px;
  line-height: 1.5;
}

button {
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff;
  background: #4f46e5;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

button:hover,
button:focus-visible {
  background: #3730a3;
}
Test the styled button

The button now looks ready to perform an action. Before you click it, what do you expect to change in the card?

  • Click Show what I'm learning in the preview.

You'll see no visible response. That shortfall is intentional.

Why doesn't the button respond?

The type="button" attribute gives the button no default action. The JAVASCRIPT panel has no project code yet.

No code is listening for the click. No code is updating the page.

You have turned plain content into a polished profile card. Next up, you'll use JavaScript to make the button deliver the response its design promises.

Make the Button Respond

Your profile card now has a polished layout. Its button still leaves the message unchanged.

The JAVASCRIPT panel in MDN Playground gives the card its missing behavior. You'll use JavaScript to connect the existing button to two visible text updates.

In this step, get ready to:
  • Select the card elements from the page.
  • Register an event listener for the button click.
  • Compare the working response with the earlier no-response button.
Connect the card elements

The DOM is the browser's live representation of the HTML elements in your preview. document.querySelector() lets your script select an element through its ID.

  • Switch back to the JAVASCRIPT panel in MDN Playground.
  • Connect the existing elements to the click response by pasting this code:
const learningButton = document.querySelector("#learning-button");
const learningMessage = document.querySelector("#learning-message");

learningButton.addEventListener("click", () => {
  learningMessage.textContent =
    "I'm learning how HTML, CSS, and JavaScript work together!";
  learningButton.textContent = "Message updated";
});

What Does This JavaScript Do?

  • learningButton stores the button selected through its ID.
  • learningMessage stores the message paragraph selected through its ID.
  • addEventListener() runs the enclosed code when the button receives a click.
  • The first textContent assignment replaces the visible message.
  • The second textContent assignment replaces the button label.
Test the click response

Before you click, consider this question: which two pieces of text will change.

  • Click Show what I'm learning in the preview.

You'll see I'm learning how HTML, CSS, and JavaScript work together! in the card. The button label becomes Message updated.

You closed the exact gap from the previous step: your polished button now responds to a real click.

Button Still Not Responding?

Compare #learning-button with the button ID in the HTML panel. Compare #learning-message with the message ID there.

Check that every opening quote has a closing quote. Check that every opening parenthesis has a closing parenthesis.

Help me debug why my profile card button does not update the text.

✔️ Awesome, I've got everything!

Your HTML, CSS, and JavaScript now work together. The button updates both visible text areas when you click it.

ⓧ I'd like to double check the full code

The complete HTML for the HTML panel is shown below:

<main class="profile-card">
  <p class="eyebrow">MY FIRST WEB PROJECT</p>
  <h1>Hi, I'm Sam.</h1>
  <p id="learning-message">I'm starting my tech journey.</p>
  <button id="learning-button" type="button">Show what I'm learning</button>
</main>

What Does This HTML Provide?

This structure contains the profile heading. It also contains the message and button targeted by JavaScript.

The complete styling for the CSS panel is shown below:

* {
  box-sizing: border-box;
}

body {
  min-height: 100vh;
  margin: 0;
  display: grid;
  place-items: center;
  padding: 24px;
  font-family: system-ui, sans-serif;
  color: #172554;
  background: #eef2ff;
}

.profile-card {
  width: 100%;
  max-width: 420px;
  padding: 32px;
  text-align: center;
  background: #ffffff;
  border-radius: 24px;
  box-shadow: 0 20px 50px rgba(30, 64, 175, 0.18);
}

.eyebrow {
  margin: 0 0 12px;
  color: #4f46e5;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.14em;
}

h1 {
  margin: 0 0 12px;
  font-size: 2.4rem;
}

#learning-message {
  min-height: 3rem;
  margin: 0 0 20px;
  line-height: 1.5;
}

button {
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff;
  background: #4f46e5;
  font: inherit;
  font-weight: 700;
  cursor: pointer;
}

button:hover,
button:focus-visible {
  background: #3730a3;
}

What Does This CSS Provide?

These rules center the card and control its visual design. The button states make the control feel clickable.

The complete interaction for the JAVASCRIPT panel is shown below:

const learningButton = document.querySelector("#learning-button");
const learningMessage = document.querySelector("#learning-message");

learningButton.addEventListener("click", () => {
  learningMessage.textContent =
    "I'm learning how HTML, CSS, and JavaScript work together!";
  learningButton.textContent = "Message updated";
});

What Does This Script Provide?

This script selects the existing elements and listens for the click. The click replaces the message and button label with the completed state.

Secret mission

Add a Theme Switch

Your card already responds to one button. Extend that event pattern with a second button that switches the entire card between light and dark themes.

Clean Up Your Resources

Clean Up Your Resources

Choose whether to keep your browser workspace available, pause your work, or clear it entirely. This browser-only project creates no paid or persistent resources, so there are no ongoing costs.

Resources you used:

  • Your current MDN Playground draft in the HTML, CSS, and JAVASCRIPT panels.

Keep everything running

Keep the existing browser tab available if you want to continue personalizing your profile card.

  • Continue editing the card in the existing Playground tab while you are actively building.
  • Test both buttons in the preview whenever you change the card.

Pause - I'll come back to this later

A browser-only project has no server or background process to stop. You can pause by leaving the existing Playground tab open.

  • Leave the Playground tab open while you step away.
  • Return to the same tab when you are ready to continue.

Delete - I don't want to use this again

Clearing the Playground removes the profile card code from this browser tab. Your Mac has no project folder or server to clean up.

  • Click Reset in the Playground toolbar to clear your work.
  • Check the preview to confirm that your profile card is gone.
  • Close the Playground browser tab.

Nice Work!

Nice Work!

You did it. Your personal profile card now responds to clicks inside MDN Playground.

You've learned how to:

  • Build a clear profile card with purposeful HTML elements.
  • Use CSS to turn plain content into a centered card with spacing. You also added colour, rounded corners, plus clear button states.
  • Diagnose the polished button's missing behavior. You added JavaScript event handling. You used DOM selection to target the card elements. You used textContent to update the visible words.
  • Secret Mission: build a two-way theme switch for light mode or dark mode. Keep its label synchronized with the next available theme.

Ready to quiz yourself?