---
id: 668f08ea07b99b1f4a91acab
title: Build a Recipe Page
challengeType: 25
dashedName: build-a-recipe-page
demoType: onClick
---

# --description--

**Objective:** Fulfill the user stories below and get all the tests to pass to complete the lab.

**User Stories:**

1. You should have a `!DOCTYPE html` declaration.
1. You should have an `html` element with `lang` set to `en`.
1. You should have a `head` element containing a `title` element with the name of your recipe, and a `meta` element with a `charset` attribute set to `UTF-8`.
1. You should have a `body` element.
1. You should have an `h1` element with the name of your recipe.
1. You should have a `p` element that introduces the recipe below the `h1`.
1. You should have one `h2` element with the text `Ingredients` for the ingredients section.
1. You should have an unordered list (`ul` element) with at least four list items (`li` elements) that lists your ingredients below the first `h2` element.
1. You should have a second `h2` element with the text `Instructions` for the instructions section.
1. You should have an ordered list (`ol` element) with at least four list items that lists the recipe steps in order, below the second `h2`.
1. You should have one `img` element with a `src` attribute set to a valid image, you can use `https://cdn.freecodecamp.org/curriculum/labs/recipe.jpg` if you would like, and an `alt` attribute describing the image.

# --hints--

Your recipe page should have a `!DOCTYPE html` declaration.

```js
assert.match(code, /<!DOCTYPE html>/i);
```

You should have an `html` element with `lang` set to `en`.

```js
assert.match(code, /<html\s+lang\s*=\s*('|")en\1\s*>[\s\S]*<\/\s*html\s*>/gi);
```

You should have a `head` element within the `html` element.

```js
assert.match(code, /<html[\s\S]*>[\s\S]*<\s*head\s*>[\s\S]*<\/\s*head\s*>[\s\S]*<\/\s*html\s*>/i);
```

You should have `title` element within your `head` element.

```js
assert.match(code, /<\s*head\s*>[\s\S]*<\s*title\s*>[\s\S]*<\/\s*title\s*>[\s\S]*<\/\s*head\s*>/i);
```

Your `title` element should have your recipe title.

```js
assert.isAbove(document.querySelector('title')?.innerText.trim().length, 0);
```

You should have a `meta` element within your `head` element.

```js
assert.match(code, /<\s*head\s*>[\s\S]*<\s*meta[\s\S]*>[\s\S]*<\/\s*head\s*>/i);
```

Your `meta` element should have its `charset` attribute set to `UTF-8`.

```js
assert.match(code, /<\s*meta[\s\S]+?charset\s*=\s*('|")UTF-8\1/i);
```

You should have a `body` element within your `html` element.

```js
assert.match(code, /<\s*html[\s\S]*>[\s\S]*<\s*head\s*>[\s\S]*<\/\s*head\s*>[\s\S]*<\s*body\s*>[\s\S]*<\/\s*body\s*>[\s\S]*<\/\s*html\s*>/i);
```

You should have an `h1` element with the name of your recipe.

```js
assert.isAbove(document.querySelector('h1')?.innerText.length, 0);
```

You should only have one `h1` element.

```js
assert.lengthOf(document.querySelectorAll('h1'), 1);
```

You should have a `p` element below your `h1` element.

```js
assert.strictEqual(document.querySelector('h1')?.nextElementSibling, document.querySelector('p'));
```

Your first `p` element should describe your recipe.

```js
assert.isNotEmpty(document.querySelector('p')?.textContent?.trim());
```

Your first `h2` element should have the text `Ingredients`.

```js
assert.equal(document.querySelectorAll('h2')[0]?.innerText, 'Ingredients');
```

You should have an unordered list element below your first `h2` element.

```js
assert.strictEqual(document.querySelector('ul')?.previousElementSibling.tagName, 'H2');
```

You should have at least four list item elements in your unordered list with the ingredients.

```js
const els = document.querySelectorAll('ul > li');
assert.isAbove(els.length, 3);
els.forEach(el => assert.isAbove(el.innerText.trim().length, 0))
```

Your second `h2` element should have the text `Instructions`.

```js
assert.equal(document.querySelectorAll('h2')[1]?.innerText, 'Instructions');
```

You should have an ordered list element below your second `h2` element.

```js
assert.strictEqual(document.querySelectorAll('h2')?.[1]?.nextElementSibling?.tagName, "OL");
```

You should have at least four list item elements in your ordered list with the instructions.

```js
const els = document.querySelectorAll('ol > li');
assert.isAbove(els.length, 3);
els.forEach(el => assert.isAbove(el.innerText.trim().length, 0))
```

You should have at least one `img` element.

```js
assert.exists(document.querySelector('img'));
```

All your `img` elements should have a valid `src` attribute and value.

```js
const img = document.querySelector('img');
const rawSrc = img?.getAttribute('src');
const resolvedSrc = img?.src;
const re = new RegExp(window.location.href, "ig");

assert.isAbove(rawSrc?.trim().length, 0, "The 'src' attribute must be explicitly set.");
assert.notMatch(resolvedSrc, re, "The 'src' should not start with the current page URL");

img.onload = () => {
  console.log('Image loaded successfully.');
};

img.onerror = (error) => {
  console.error('Image failed to load:', error);
  assert.fail("Your image's URL should be valid."); // Make the test instafail
};

if (img.complete) {
  img.onload && img.onload();
};
```

All your `img` elements should have an `alt` attribute to describe the image.

```js
assert.isAbove(document.querySelector('img')?.alt.length, 0);
```

# --seed--

## --seed-contents--

```html

```

# --solutions--

```html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <title>Chocolate chip cookies recipe</title>
</head>

<body>
  <h1>Chocolate Chip Cookies</h1>
  <p>Welcome to the ultimate guide for making mini chocolate chip cookies! These bite-sized treats are perfect for
    satisfying your sweet tooth without overindulging. Follow this simple recipe to create delicious,
    crispy-on-the-outside, chewy-on-the-inside mini chocolate chip cookies that everyone will love.</p>
  <img src="https://cdn.freecodecamp.org/curriculum/labs/recipe.jpg" alt="Ingredients for baking: three eggs, a bowl of flour, a glass of milk, and a whisk arranged on a wooden table.">
  <h2>Ingredients</h2>
  <ul>
    <li>1 cup all-purpose flour</li>
    <li>1/2 teaspoon baking soda</li>
    <li>1/4 cup unsalted butter, softened</li>
    <li>1/4 cup granulated sugar</li>
    <li>1/2 teaspoon vanilla extract</li>
    <li>1/2 cup mini chocolate chips</li>
  </ul>
  <h2>Instructions</h2>
  <ol>
    <li>Preheat your oven to 350°F (175°C) and line a baking sheet with parchment paper.</li>
    <li>In a bowl, whisk together the flour and baking soda.</li>
    <li>In another bowl, beat the butter, sugar, and vanilla extract until creamy.</li>
    <li>Gradually add the dry ingredients to the wet mixture, then fold in the mini chocolate chips.</li>
    <li>Drop small spoonfuls of dough onto the baking sheet.</li>
    <li>Bake for 8-10 minutes, then let cool before enjoying!</li>
  </ol>
</body>

</html>
```
