An order form is a contact form with arithmetic attached, and the arithmetic is where it gets interesting. The markup is ordinary: number inputs for quantities, a select or a group of radios for options, address fields, and a submit button. What is not ordinary is that some of these values are about to be turned into money, and every value in a form arrives from a browser you do not control.
Line items and quantities in plain markup
Each line is a control with a name that identifies the product and a value that is the quantity. Use type="number" with min and step so the browser offers the right keyboard and refuses obvious nonsense, and give each one a label naming the product rather than saying Quantity three times. If the customer chooses between variants, that is a group of radios inside a fieldset whose legend names the choice, or a select if the list is long. Keep the names predictable, because the other end has to turn them back into an order.
Never let the form decide the price
The tempting shortcut is a hidden input holding the price, so the receiving end can just add it up. Do not. A hidden input is a value the browser sent, and anybody can change it before submitting; there is a long history of shops discovering this in the worst possible way. Send the product identifier and the quantity, and look the price up yourself on the other side. Show the total on the page by all means, as a convenience, but treat what comes back as a request rather than an invoice.
An order form is not a checkout
A form can collect what somebody wants to buy. It cannot take a card, and it must not try: card details in a form you receive puts you inside a compliance perimeter you almost certainly do not want to be in. The usual shape is that the form records the order and then hands off to a payment provider that owns the card fields, or that you invoice afterwards. Decide which of those you are doing before you write the markup, because it changes what the form has to ask for.
Confirm in a way somebody can keep
An order needs a reference and a record on both sides. The page that answers the submission should show what was ordered and a reference number, and the same thing should arrive by email, because people close tabs. Keep the submission somewhere you can search later, since the questions that come three weeks afterwards are always about an order nobody can find. This is the point at which a form that only emails you starts to hurt.
Questions people ask about html order form
Can I calculate the total in JavaScript?
Yes, for the visitor's benefit. Just never trust the result: recalculate on the receiving end from the product identifiers and quantities, using prices you hold, because the number the browser sent is only ever a claim.
Should the order form take card details?
No. Handle payment with a provider whose fields collect the card, so the details never reach your server. An order form's job is to say what is wanted and by whom.
How do I stop somebody ordering a negative quantity?
min="1" on the number input stops the honest mistake in the browser, and a check on the receiving end stops the rest. Both, always: the attribute is a courtesy and the server-side check is the rule.