Tangy is building your next step
Shaping the lesson around what you want to make.
Tangy is building your next step
Shaping the lesson around what you want to make.
Computer Science
From your solid HTML/CSS foundation, you’ll create a compact, accessible landing page and add a client‑side contact form that validates inputs and shows inline messages – all without any backend.
Semantic Markup Foundations
2 lessonsLay the structural groundwork for the landing page using only semantic HTML elements.
Styling the Landing Page
3 lessonsUse modern CSS selectors and layout modules to turn the markup into a compact, responsive design.
Vanilla JavaScript Form Validation
4 lessonsAdd client‑side logic that validates input, shows inline feedback, and clears the form on success.
Public lesson
Your HTML project already demonstrated that you can build a document structure. This time, make the structure describe the page’s purpose clearly—not just how it happens to look. Keep your existing class names where possible so your CSS selectors continue to work.
Tasks
Open your current index.html. On paper or in a note, match each visible area to one of these roles:
Tasks
Now inspect your current markup. For each area, write down:
class or id must remain for your CSS?For example:
| Page area | Semantic element | Existing selector to preserve |
|---|---|---|
| Site navigation | <header> and <nav> | your current navigation class |
| Main introduction | <section> inside <main> | your hero class |
| Repeated feature | <article> | your feature-card class |
You already know CSS selectors, so this is a chance to practice changing the HTML structure without accidentally disconnecting the styles.
Tasks
In index.html, create a semantic structure like this. The comments show decisions you still need to make; do not leave them as the final page content.
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><!-- write the page title --></title>
<link rel="stylesheet" href="<!-- keep your stylesheet path -->">
</head>
<body>
<header>
<!-- site name or logo -->
<nav aria-label="Primary navigation">
<!-- add links to the page sections -->
</nav>
</header>
<main>
<section id="hero" aria-labelledby="hero-title">
<h1 id="hero-title"><!-- write the page's main heading --></h1>
<!-- add the hero description and primary action -->
</section>
<section id="features" aria-labelledby="features-title">
<h2 id="features-title"><!-- write the features heading --></h2>
<!-- create one article for each repeated feature -->
</section>
<section id="contact" aria-labelledby="contact-title">
<h2 id="contact-title"><!-- write the contact heading --></h2>
<!-- add supporting contact text -->
<form action="#" method="post">
<!-- add a labeled name field -->
<!-- add a labeled email field -->
<!-- add a labeled message field -->
<!-- add a submit button -->
</form>
</section>
</main>
<footer>
<!-- add the footer content -->
</footer>
</body>
</html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><!-- write the page title --></title>
<link rel="stylesheet" href="<!-- keep your stylesheet path -->">
</head>
<body>
<header>
<!-- site name or logo -->
<nav aria-label="Primary navigation">
<!-- add links to the page sections -->
</nav>
</header>
<main>
<section id="hero" aria-labelledby="hero-title">
<h1 id="hero-title"><!-- write the page's main heading --></h1>
<!-- add the hero description and primary action -->
</section>
<section id="features" aria-labelledby="features-title">
<h2 id="features-title"><!-- write the features heading --></h2>
<!-- create one article for each repeated feature -->
</section>
<section id="contact" aria-labelledby="contact-title">
<h2 id="contact-title"><!-- write the contact heading --></h2>
<!-- add supporting contact text -->
<form action="#" method="post">
<!-- add a labeled name field -->
<!-- add a labeled email field -->
<!-- add a labeled message field -->
<!-- add a submit button -->
</form>
</section>
</main>
<footer>
<!-- add the footer content -->
</footer>
</body>
</html>
Use your project’s real content rather than inventing a new page. A semantic element should describe the purpose of its content:
<header> for introductory or navigational content.<main> for the page’s central content.<section> for each major, named area.<article> for each feature that could make sense as a separate item.<footer> for closing information.<nav> around navigation links.<form> around controls that collect information.Tasks
Save the file and refresh the page.
The page may look different if your old CSS depended on a wrapper such as <div>. That is useful evidence, not a failure. Use the browser inspector to check:
<main>?<main>?If a style disappeared, compare the old and new class names. Restore the class on the new semantic element instead of adding unnecessary wrapper elements.
Tasks
Inside the features section, create an <article> for every feature card. Each article should have its own heading.
A feature section should have this shape, adapted to your project’s content and class names:
<section class="your-features-class" id="features" aria-labelledby="features-title">
<h2 id="features-title">Your features heading</h2>
<article class="your-card-class">
<h3>First feature</h3>
<p>Description of the first feature.</p>
</article>
<!-- add the remaining feature articles -->
</section>
<section class="your-features-class" id="features" aria-labelledby="features-title">
<h2 id="features-title">Your features heading</h2>
<article class="your-card-class">
<h3>First feature</h3>
<p>Description of the first feature.</p>
</article>
<!-- add the remaining feature articles -->
</section>
Do not copy the example’s class names unless they match your project. The important relationship is:
section heading → repeated article → article heading and content
Tasks
Refresh the page and confirm that every feature still appears. In the inspector, expand the features section and count the <article> elements.
Tasks
A form is more usable when someone can identify each control even without relying on placeholder text. For each control:
<label> a for value.id.name value.required where the field must be completed.Tasks
Create your fields using this pattern, changing the names and wording to fit your project:
<label for="your-field-id">Your field label</label>
<input id="your-field-id" name="your-field-name" type="text" required>
<label for="your-field-id">Your field label</label>
<input id="your-field-id" name="your-field-name" type="text" required>
For the email field, use type="email". For a longer message, use <textarea> rather than a single-line <input>.
Tasks
Your form should contain:
The form does not need a working backend yet. Its job in this lesson is to have clear, valid structure.
Tasks
Click each label in the browser. The corresponding input should receive focus. If it does not, the label’s for value and control’s id do not match exactly.
Tasks
Give each navigation link an href that points to one of your section IDs:
<a href="#your-section-id">Your link text</a>
<a href="#your-section-id">Your link text</a>
Make sure the destination ID exists exactly once. Test every link by clicking it. The browser should move to the matching section.
Tasks
Use the Nu HTML Checker at validator.w3.org/nu. Upload your index.html or validate its local source.
Tasks
Fix errors one at a time. In particular, look for:
id valuesfor value does not match an input idalt text on images, if your page has imagesWarnings are worth reading, but first get the document to zero errors.
Your index.html meets all of these checks:
<header>, one <main>, and one <footer>.<section> elements.<article>.3 modules · 9 lessons
Semantic Markup Foundations
Styling the Landing Page
Vanilla JavaScript Form Validation
Learn by building your own version.
Remix this public project to open the workspace, follow the guided build, and let the AI mentor teach you through the work instead of doing it for you.