# Exercise: A Pizza Order Form

Build Slice of Heaven Pizza's online order form with radio buttons, checkboxes, a dropdown, typed inputs and a text area, then send it and see exactly what the kitchen receives.

Apprentice · HTML · Updated October 30, 2026

Slice of Heaven Pizza takes every order by phone, and on a Friday night the line is always busy. The owner wants an order form on the website: pick a size, a crust and toppings, say how many, choose delivery or pickup, and tell the driver where the blue door is. You'll build it, choosing the right control for every question, and a ready-made page shows you exactly what the kitchen would receive. Tests check your form as you go.

## Before you start

The tests run with Node.js, which you installed in *Setup: VS Code, a Browser and Node.js*. If you skipped that lesson, install Node.js first.

## Get the exercise code

In the **Exercise** box beside the lesson, choose **Get the starter on GitHub** to open its GitHub repository. Click **Code**, then **Download ZIP**, and unzip it. Then open the folder in **VS Code**.

| File | What's in it |
|---|---|
| `index.html` | The order page: a header, a footer, and an empty `<form>` tag. For you to finish. |
| `menu.txt` | Every question the form asks, with the names and values the kitchen's computer expects |
| `received.html` | The page the form sends to. It shows, as a table, every name and value it received. |
| `style.css` | The styles for both pages, so a well-built form looks good on its own |
| `page.test.js`, `package.json` | The tests and the tools they use. You don't need to change these. |

## What to do

The form tag is already in `index.html`, and it sends to `received.html`:

```html
<form action="received.html" method="get">
  <!--
    Build the order form here, inside the form tag.
    menu.txt lists every question the kitchen needs answered, with the names and values its computer expects.
    README.md says which control each question gets.
  -->
</form>
```

Build the form inside it, one question at a time, with the names and values from `menu.txt`:

1. **Size:** three radio buttons, grouped in a fieldset with a legend. Medium, the size most people order, starts chosen.
2. **Crust:** a dropdown of the four crusts.
3. **Toppings:** a checkbox for each of the eight toppings, grouped in a fieldset with a legend.
4. **How many pizzas:** a number box that takes 1 to 10.
5. **Delivery or pickup:** two radio buttons, grouped in a fieldset with a legend.
6. **Ready by:** a time between 11:00 and 22:00.
7. **Your details:** a name, a phone number, an email for the receipt, a house number and a street, each with the input type that fits it.
8. **Notes for the driver:** a text area, four rows tall.
9. **A button** that sends the form.

Every control gets a label the visitor can read. Open `index.html` with Live Server after each step, send the form, and look at what `received.html` shows.

**Stretch goal:** make the street box suggest the six streets at the end of `menu.txt`, while still letting a visitor type any street.

## Check your work

Open VS Code's terminal (**Terminal > New Terminal**) and run:

```bash
npm install
npm test
```

You only need `npm install` once: it downloads the two tools the tests use. At first most tests fail, and that's expected. Each part of the form you build turns its test green. A failing test's message says what it looked for, for example *Add at least 3 radio buttons with name="size" (found 0).*

The last test runs the HTML validator over your page, the same kind of check as in *Validating Your Page*, so a misspelled type or a tag left open shows up there.

The tests can't click, so check these in the browser:

- Clicking a label picks its radio button or ticks its checkbox.
- Only one size, and only one of delivery or pickup, can be chosen at a time.
- With the keyboard alone (**Tab**, the arrow keys and **Space**), you can fill in the whole form and send it.
- Asking for 11 pizzas, or a time of 23:30, stops the form with a message from the browser.

## Hints

- **One name, one group.** Radio buttons that share a `name` are one question. Their `value` is what the kitchen gets, and their label is what the visitor reads. See *Checkboxes, Radio Buttons and Fieldsets*.
- **Every choice is a pair.** Each radio button and each checkbox gets its own `<label>`, tied to it with `for` and its own `id`. Eight toppings means eight ids.
- **The legend comes first.** It's the first thing inside its `<fieldset>`, and it asks the question in a word or two.
- **Would you add 1 to it?** If not, it isn't a number box. That settles the phone number and the house number (42B is a real house number). *Input Types for Email, Numbers, Dates and More* has the rule.
- **A dropdown names itself once.** The `name` goes on the `<select>`, and each `<option>` gets a `value`. See *Dropdowns, Text Areas and Suggestions*.
- **Keep the text area's tags together.** Anything between `<textarea>` and `</textarea>` starts out in the box, spaces included.

## When you're done

Every test is green:

```text
✔ 1) form: sends the order to received.html
✔ 2) size: radio buttons named size, each with its own value and label
✔ 3) size: in a fieldset with a legend
✔ 4) toppings: checkboxes named topping, each with its own value and label
✔ 5) toppings: in a fieldset with a legend
✔ 6) crust: a dropdown named crust, every option with a value
✔ 7) delivery or pickup: two radio buttons, in a fieldset with a legend
✔ 8) quantity: a number input from 1 to 10
✔ 9) input types: each fits its question
✔ 10) driver notes: a text area named driver_notes
✔ 11) every control: has a name and a label
✔ 12) button: sends the form
✔ 13) the page: passes the HTML validator
ℹ tests 13
ℹ pass 13
ℹ fail 0
```

Order two large thin-crust pizzas with pepperoni and basil, for delivery at 18:30 to 42B Maple Avenue, and `received.html` shows the kitchen's side of it:

```text
size                large
crust               thin
topping             pepperoni
topping             basil
quantity            2
delivery_or_pickup  delivery
ready_time          18:30
customer_name       Jordan
phone               (801) 555-0142
email               jordan@example.com
house_number        42B
street              Maple Avenue
driver_notes        Blue door, around the back.
```

Look at the `topping` rows: two of them, and none for the six toppings you didn't tick. Now look back at your form. Is there a question where a different control would have worked too? Why did you pick the one you did?

## So what

You've built the kind of form that most online businesses run on, and every answer reaches the kitchen in a shape its computer can read. Choosing the control that fits each question is a habit that pays off on every checkout, sign-up and survey you build from here.

## Key terms

- [Radio button](https://www.ask-codey.com/glossary/radio-button)
- [Checkbox](https://www.ask-codey.com/glossary/checkbox)
- [&lt;fieldset>](https://www.ask-codey.com/glossary/fieldset)
- [&lt;select>](https://www.ask-codey.com/glossary/select-html)
- [&lt;textarea>](https://www.ask-codey.com/glossary/textarea)
- [Input type](https://www.ask-codey.com/glossary/input-type)

## Related

- [Input Types for Email, Numbers, Dates and More](https://www.ask-codey.com/lessons/html-forms-input-types)
- [Checkboxes, Radio Buttons and Fieldsets](https://www.ask-codey.com/lessons/html-forms-checkboxes-radios-and-fieldsets)
- [Dropdowns, Text Areas and Suggestions](https://www.ask-codey.com/lessons/html-forms-select-textarea-and-datalist)

Source: https://www.ask-codey.com/lessons/exercise-html-pizza-order-form
