Lesson Goal
A portfolio website is a personal website that presents who you are, what you can do, and what you have built. It is one of the best beginner frontend projects because it combines page structure, styling, responsiveness, and interactivity.
What students should learn
- How to structure a page with semantic HTML
- How CSS turns plain content into a polished layout
- How JavaScript adds interaction
- How to build a project in small steps
Before starting
- Create a file named index.html
- Open it in a browser
- Open the live editor below
- After each step, save and refresh the page
Live HTML Preview Editor
Students can paste the code from any lesson step into this editor and preview it immediately. This is useful for testing layout, experimenting with styles, and understanding how the page changes as each step is added.
Embedded HTML Preview Editor
How to use it
- Copy code from any step below.
- Paste it into the embedded editor.
- Run or preview the result.
- Make changes and compare how the output improves step by step.
Step 0 — Create the basic HTML page
We begin with the smallest valid page.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>My Portfolio</title>
</head>
<body>
<h1>My Portfolio</h1>
<p>This is the beginning of my website.</p>
</body>
</html>
Check
After saving and refreshing, you should see a heading that says My Portfolio and a short paragraph below it.
Step 1 — Add page sections
Now we organize the page into meaningful parts.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>My Portfolio</title>
</head>
<body>
<header>
<h1>My Portfolio</h1>
<p>Frontend Student</p>
</header>
<main>
<section>
<h2>About Me</h2>
<p>I am learning HTML, CSS, and JavaScript.</p>
</section>
<section>
<h2>Skills</h2>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
</section>
<section>
<h2>Projects</h2>
<p>My projects will go here.</p>
</section>
<section>
<h2>Contact</h2>
<p>Email: student@example.com</p>
</section>
</main>
<footer>
<p>© 2026 My Portfolio</p>
</footer>
</body>
</html>
Check
Your page should now have 4 content areas: About Me, Skills, Projects, and Contact.
Step 2 — Add navigation links
This makes the portfolio easier to move around.
<header>
<h1>My Portfolio</h1>
<p>Frontend Student</p>
<nav>
<a href="#about">About</a>
<a href="#skills">Skills</a>
<a href="#projects">Projects</a>
<a href="#contact">Contact</a>
</nav>
</header>
<main>
<section id="about">
<h2>About Me</h2>
<p>I am learning HTML, CSS, and JavaScript.</p>
</section>
<section id="skills">
<h2>Skills</h2>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
</section>
<section id="projects">
<h2>Projects</h2>
<p>My projects will go here.</p>
</section>
<section id="contact">
<h2>Contact</h2>
<p>Email: student@example.com</p>
</section>
</main>
Check
Clicking each navigation link should move you to the matching section.
Step 3 — Add CSS to make it look like a real site
Now we style the structure we built.
<style>
:root{
--bg:#fff8ef;
--panel:#ffffff;
--ink:#1f2937;
--muted:#6b7280;
--brand:#d97706;
--line:#ead7c4;
}
*{box-sizing:border-box}
body{
margin:0;
font-family:Arial, Helvetica, sans-serif;
background:var(--bg);
color:var(--ink);
line-height:1.6;
}
.container{
width:min(1000px, calc(100% - 32px));
margin:0 auto;
}
header{
background:#fff;
border-bottom:1px solid var(--line);
padding:20px 0;
}
nav a{
margin-right:14px;
text-decoration:none;
color:var(--brand);
font-weight:bold;
}
section{
background:var(--panel);
border:1px solid var(--line);
border-radius:18px;
padding:24px;
margin:24px 0;
}
h1,h2,h3{
margin-top:0;
}
.btn{
display:inline-block;
background:var(--brand);
color:#fff;
text-decoration:none;
padding:12px 16px;
border-radius:12px;
font-weight:bold;
}
footer{
text-align:center;
padding:24px 0 40px;
color:var(--muted);
}
</style>
How to use this CSS
Put this inside the <head> section of your page, and wrap your content inside a div with class container.
Check
Your page should now have padding, section cards, soft colors, and a cleaner layout.
Step 4 — Add a hero section and project cards
This makes the portfolio feel complete and modern.
<section id="home">
<h2>Hello, I am Your Name</h2>
<p>I build beginner-friendly frontend projects using HTML, CSS, and JavaScript.</p>
<a class="btn" href="#projects">View My Projects</a>
</section>
<section id="projects">
<h2>Projects</h2>
<div class="projects-grid">
<article class="project-card">
<h3>Portfolio Website</h3>
<p>A personal website to showcase my profile and work.</p>
</article>
<article class="project-card">
<h3>Quiz App</h3>
<p>A multiple-choice quiz app built with JavaScript.</p>
</article>
<article class="project-card">
<h3>Mini Shop UI</h3>
<p>A frontend shopping page with product cards and cart ideas.</p>
</article>
</div>
</section>
#home{
text-align:left;
}
.projects-grid{
display:grid;
grid-template-columns:repeat(3, 1fr);
gap:16px;
}
.project-card{
border:1px solid var(--line);
border-radius:16px;
padding:18px;
background:#fffdf9;
}
@media (max-width: 800px){
.projects-grid{
grid-template-columns:1fr;
}
}
Check
You should now see a top introduction area and three project cards arranged in a grid.
Step 5 — Add a contact form
A portfolio should make it easy for people to reach you.
<section id="contact">
<h2>Contact Me</h2>
<form id="contactForm">
<p>
<label for="name">Name</label><br />
<input id="name" type="text" placeholder="Enter your name" />
</p>
<p>
<label for="email">Email</label><br />
<input id="email" type="email" placeholder="Enter your email" />
</p>
<p>
<label for="message">Message</label><br />
<textarea id="message" rows="5" placeholder="Write your message"></textarea>
</p>
<button class="btn" type="submit">Send Message</button>
<p id="formMessage"></p>
</form>
</section>
input, textarea{
width:100%;
padding:12px;
border:1px solid var(--line);
border-radius:12px;
font:inherit;
}
label{
font-weight:bold;
}
#formMessage{
color:green;
font-weight:bold;
}
Check
Your contact section should now contain inputs for name, email, and message.
Step 6 — Add JavaScript interaction
Now the page starts reacting to user actions.
- form validation
- a success message
- a theme toggle button
- theme saving with localStorage
<button id="themeToggle" class="btn" type="button">Toggle Theme</button>
body.dark{
--bg:#111827;
--panel:#1f2937;
--ink:#f9fafb;
--muted:#d1d5db;
--brand:#f59e0b;
--line:#374151;
}
<script>
const contactForm = document.getElementById("contactForm");
const formMessage = document.getElementById("formMessage");
const themeToggle = document.getElementById("themeToggle");
function applyTheme(theme) {
if (theme === "dark") {
document.body.classList.add("dark");
} else {
document.body.classList.remove("dark");
}
}
const savedTheme = localStorage.getItem("portfolio-theme") || "light";
applyTheme(savedTheme);
themeToggle.addEventListener("click", function () {
const isDark = document.body.classList.contains("dark");
const nextTheme = isDark ? "light" : "dark";
localStorage.setItem("portfolio-theme", nextTheme);
applyTheme(nextTheme);
});
contactForm.addEventListener("submit", function (event) {
event.preventDefault();
const name = document.getElementById("name").value.trim();
const email = document.getElementById("email").value.trim();
const message = document.getElementById("message").value.trim();
if (!name || !email || !message) {
formMessage.textContent = "Please fill in all fields.";
return;
}
if (!email.includes("@") || !email.includes(".")) {
formMessage.textContent = "Please enter a valid email address.";
return;
}
formMessage.textContent = "Your message has been saved on the frontend.";
contactForm.reset();
});
</script>
Check
- Click the theme button and the page colors should change.
- Refresh the page and the theme should stay saved.
- Submit an empty form and you should see a warning.
- Submit a filled form and you should see a success message.
Final Build — Complete Single HTML Page
This is the complete finished lesson result. It includes HTML, CSS, and JavaScript in one file. Students can copy this into index.html, save it, and run it directly.
Student Portfolio
Hello, I am Your Name
I build websites using HTML, CSS, and JavaScript.
Who you are
What you know
What you built
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Student Portfolio</title>
<meta name="description" content="A beginner portfolio website built with HTML, CSS, and JavaScript." />
<style>
:root{
--bg:#fff8ef;
--panel:#ffffff;
--soft:#fff2df;
--ink:#1f2937;
--muted:#6b7280;
--brand:#d97706;
--brand-dark:#b45309;
--line:#ead7c4;
--shadow:0 10px 28px rgba(0,0,0,.08);
}
body.dark{
--bg:#111827;
--panel:#1f2937;
--soft:#172033;
--ink:#f9fafb;
--muted:#d1d5db;
--brand:#f59e0b;
--brand-dark:#d97706;
--line:#374151;
--shadow:0 10px 28px rgba(0,0,0,.28);
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{
margin:0;
font-family:Arial, Helvetica, sans-serif;
background:var(--bg);
color:var(--ink);
line-height:1.6;
}
img{
max-width:100%;
display:block;
border-radius:20px;
}
a{
text-decoration:none;
color:inherit;
}
.container{
width:min(1100px, calc(100% - 32px));
margin:0 auto;
}
.site-header{
position:sticky;
top:0;
z-index:1000;
background:rgba(255,248,239,.92);
backdrop-filter:blur(10px);
border-bottom:1px solid var(--line);
}
body.dark .site-header{
background:rgba(17,24,39,.92);
}
.nav-wrap{
display:flex;
justify-content:space-between;
align-items:center;
gap:14px;
min-height:72px;
}
.logo{
color:var(--brand);
font-size:1.35rem;
font-weight:800;
}
.nav{
display:flex;
gap:16px;
align-items:center;
flex-wrap:wrap;
}
.nav a{
font-weight:700;
color:var(--muted);
}
.nav a:hover{
color:var(--brand);
}
.menu-btn{
display:none;
border:none;
background:var(--panel);
color:var(--ink);
padding:10px 12px;
border-radius:12px;
cursor:pointer;
box-shadow:var(--shadow);
font-size:1.2rem;
}
.btn{
border:none;
background:var(--brand);
color:#fff;
padding:12px 16px;
border-radius:12px;
cursor:pointer;
font-weight:800;
transition:transform .2s ease, background .2s ease;
}
.btn:hover{
transform:translateY(-2px);
background:var(--brand-dark);
}
.btn-outline{
background:transparent;
color:var(--brand);
border:2px solid var(--brand);
}
.btn-outline:hover{
color:#fff;
}
.section{
padding:72px 0;
}
.section-soft{
background:var(--soft);
}
.hero-grid{
display:grid;
grid-template-columns:1.15fr .85fr;
gap:24px;
align-items:center;
}
.hero h1{
margin:0 0 10px;
font-size:clamp(2rem,5vw,3.5rem);
line-height:1.12;
}
.eyebrow{
color:var(--brand);
font-weight:800;
margin-bottom:8px;
}
.accent{
color:var(--brand);
}
.hero-desc,
.section-text{
color:var(--muted);
max-width:720px;
}
.hero-actions{
display:flex;
gap:12px;
flex-wrap:wrap;
margin-top:20px;
}
.hero-card,
.skill-card,
.project-card,
.contact-form{
background:var(--panel);
border:1px solid var(--line);
border-radius:22px;
box-shadow:var(--shadow);
}
.hero-card{
padding:18px;
min-height:320px;
display:grid;
place-items:center;
text-align:center;
background:
linear-gradient(135deg, rgba(245,158,11,.10), rgba(255,255,255,.55)),
var(--panel);
}
.skills-grid,
.projects-grid{
display:grid;
gap:20px;
}
.skills-grid{
grid-template-columns:repeat(2,1fr);
}
.projects-grid{
grid-template-columns:repeat(3,1fr);
}
.skill-card,
.project-card{
padding:20px;
}
.bar{
height:12px;
background:#e5e7eb;
border-radius:999px;
overflow:hidden;
margin-top:10px;
}
.bar span{
display:block;
height:100%;
background:linear-gradient(90deg,var(--brand),#fbbf24);
border-radius:999px;
}
.project-card p{
color:var(--muted);
}
.project-link{
display:inline-block;
margin-top:10px;
color:var(--brand);
font-weight:800;
}
.contact-form{
padding:24px;
max-width:760px;
}
.form-row{
display:grid;
gap:8px;
margin-bottom:16px;
}
label{
font-weight:800;
}
input,
textarea{
width:100%;
padding:14px;
border-radius:12px;
border:1px solid var(--line);
background:transparent;
color:var(--ink);
font:inherit;
}
input:focus,
textarea:focus{
outline:2px solid rgba(217,119,6,.18);
border-color:var(--brand);
}
.form-message{
margin-top:14px;
font-weight:800;
color:var(--brand);
}
.site-footer{
border-top:1px solid var(--line);
padding:22px 0;
text-align:center;
color:var(--muted);
}
@media (max-width: 860px){
.hero-grid,
.skills-grid,
.projects-grid{
grid-template-columns:1fr;
}
.menu-btn{
display:inline-block;
}
.nav{
position:absolute;
top:72px;
left:16px;
right:16px;
display:none;
flex-direction:column;
align-items:stretch;
background:var(--panel);
border:1px solid var(--line);
padding:16px;
border-radius:18px;
box-shadow:var(--shadow);
}
.nav.show{
display:flex;
}
}
</style>
</head>
<body>
<header class="site-header">
<div class="container nav-wrap">
<a href="#" class="logo">MyPortfolio</a>
<button class="menu-btn" id="menuBtn" aria-label="Open navigation">☰</button>
<nav class="nav" id="nav">
<a href="#home">Home</a>
<a href="#about">About</a>
<a href="#skills">Skills</a>
<a href="#projects">Projects</a>
<a href="#contact">Contact</a>
<button id="themeToggle" class="btn" type="button">🌙 Theme</button>
</nav>
</div>
</header>
<main>
<section class="section hero" id="home">
<div class="container hero-grid">
<div>
<p class="eyebrow">Student Portfolio</p>
<h1>Hello, I am <span class="accent">Your Name</span></h1>
<p class="hero-desc">
I am learning frontend development and building websites using HTML, CSS, and JavaScript.
</p>
<div class="hero-actions">
<a href="#projects" class="btn">View Projects</a>
<a href="#contact" class="btn btn-outline">Contact Me</a>
</div>
</div>
<div class="hero-card">
<div>
<img src="https://via.placeholder.com/420x320.png?text=Your+Photo" alt="Student placeholder image" />
</div>
</div>
</div>
</section>
<section class="section" id="about">
<div class="container">
<h2>About Me</h2>
<p class="section-text">
I enjoy creating websites, solving problems, and learning modern frontend development.
</p>
</div>
</section>
<section class="section section-soft" id="skills">
<div class="container">
<h2>My Skills</h2>
<div class="skills-grid">
<div class="skill-card">
<h3>HTML</h3>
<div class="bar"><span style="width:90%"></span></div>
</div>
<div class="skill-card">
<h3>CSS</h3>
<div class="bar"><span style="width:82%"></span></div>
</div>
<div class="skill-card">
<h3>JavaScript</h3>
<div class="bar"><span style="width:72%"></span></div>
</div>
<div class="skill-card">
<h3>Problem Solving</h3>
<div class="bar"><span style="width:85%"></span></div>
</div>
</div>
</div>
</section>
<section class="section" id="projects">
<div class="container">
<h2>My Projects</h2>
<div class="projects-grid">
<article class="project-card">
<h3>Portfolio Website</h3>
<p>A personal website to present my profile, skills, and work.</p>
<a href="#" class="project-link">View Project</a>
</article>
<article class="project-card">
<h3>Quiz App</h3>
<p>An interactive quiz project built with JavaScript.</p>
<a href="#" class="project-link">View Project</a>
</article>
<article class="project-card">
<h3>Mini Shop UI</h3>
<p>A product listing page with cards and frontend interactions.</p>
<a href="#" class="project-link">View Project</a>
</article>
</div>
</div>
</section>
<section class="section section-soft" id="contact">
<div class="container">
<h2>Contact Me</h2>
<form class="contact-form" id="contactForm">
<div class="form-row">
<label for="name">Name</label>
<input id="name" type="text" placeholder="Enter your name" />
</div>
<div class="form-row">
<label for="email">Email</label>
<input id="email" type="email" placeholder="Enter your email" />
</div>
<div class="form-row">
<label for="message">Message</label>
<textarea id="message" rows="5" placeholder="Write your message"></textarea>
</div>
<button class="btn" type="submit">Send Message</button>
<p class="form-message" id="formMessage"></p>
</form>
</div>
</section>
</main>
<footer class="site-footer">
<div class="container">
<p>© 2026 Your Name | Student Portfolio</p>
</div>
</footer>
<script>
const menuBtn = document.getElementById("menuBtn");
const nav = document.getElementById("nav");
const themeToggle = document.getElementById("themeToggle");
const contactForm = document.getElementById("contactForm");
const formMessage = document.getElementById("formMessage");
menuBtn.addEventListener("click", () => {
nav.classList.toggle("show");
});
document.querySelectorAll(".nav a").forEach((link) => {
link.addEventListener("click", () => {
nav.classList.remove("show");
});
});
function applyTheme(theme) {
if (theme === "dark") {
document.body.classList.add("dark");
themeToggle.textContent = "☀️ Light";
} else {
document.body.classList.remove("dark");
themeToggle.textContent = "🌙 Theme";
}
}
const savedTheme = localStorage.getItem("portfolio-theme") || "light";
applyTheme(savedTheme);
themeToggle.addEventListener("click", () => {
const isDark = document.body.classList.contains("dark");
const nextTheme = isDark ? "light" : "dark";
localStorage.setItem("portfolio-theme", nextTheme);
applyTheme(nextTheme);
});
contactForm.addEventListener("submit", (event) => {
event.preventDefault();
const name = document.getElementById("name").value.trim();
const email = document.getElementById("email").value.trim();
const message = document.getElementById("message").value.trim();
if (!name || !email || !message) {
formMessage.textContent = "Please fill in all fields.";
return;
}
if (!email.includes("@") || !email.includes(".")) {
formMessage.textContent = "Please enter a valid email address.";
return;
}
formMessage.textContent = "Thank you. Your message has been recorded on the frontend.";
contactForm.reset();
});
</script>
</body>
</html>
Final Check
- The page has a header, hero, about, skills, projects, contact, and footer.
- The site is responsive on mobile screens.
- The theme toggle works and stays saved after refresh.
- The contact form validates user input.
Practice Tasks for Students
Basic tasks
- Replace placeholder name and text
- Add a real profile image
- Add one more project card
- Add social links
Upgrade tasks
- Add a certificates section
- Add hover animation on cards
- Add a download CV button
- Add a skills progress animation