A checkout is three small forms in sequence, each with one actions row. The field groups
lean on autocomplete address and card tokens, which is what lets a browser
fill the whole shipping step from one saved profile. City, state, and ZIP share a grid
because they submit together; the labels and ids stay one-field units inside it.
Shipping address
The one optional line is marked in its label, per the field unit; the rest are required and get the marker.
Shipping address
<div class="card center" style="--center-max: 40rem">
<div class="flow">
<h2>Shipping address</h2>
<form class="stack">
<div class="stack is-tight">
<label for="ship-name">Full name</label>
<input
id="ship-name"
type="text"
class="input"
required
autocomplete="name"
/>
</div>
<div class="stack is-tight">
<label for="ship-street1">Address</label>
<input
id="ship-street1"
type="text"
class="input"
required
autocomplete="address-line1"
/>
</div>
<div class="stack is-tight">
<label for="ship-street2">Apt, suite, etc. (optional)</label>
<input
id="ship-street2"
type="text"
class="input"
autocomplete="address-line2"
/>
</div>
<div class="grid" style="--grid-min: 10rem">
<div class="stack is-tight">
<label for="ship-city">City</label>
<input
id="ship-city"
type="text"
class="input"
required
autocomplete="address-level2"
/>
</div>
<div class="stack is-tight">
<label for="ship-state">State</label>
<input
id="ship-state"
type="text"
class="input"
required
autocomplete="address-level1"
/>
</div>
<div class="stack is-tight">
<label for="ship-zip">ZIP</label>
<input
id="ship-zip"
type="text"
class="input"
required
inputmode="numeric"
autocomplete="postal-code"
/>
</div>
</div>
<div class="stack is-tight">
<label for="ship-country">Country</label>
<select id="ship-country" class="input" required autocomplete="country">
<option>United States</option>
<option>Canada</option>
<option>Mexico</option>
<option>United Kingdom</option>
</select>
</div>
<div class="cluster is-end">
<button class="button is-ghost" type="button">Cancel</button>
<button class="button" type="submit">Continue to payment</button>
</div>
</form>
</div>
</div>
Payment method
The card number gets its own row; expiry and CVC share a grid, the same pairing as the city row above.
Payment method
<div class="card center" style="--center-max: 40rem">
<div class="flow">
<h2>Payment method</h2>
<form class="stack">
<div class="stack is-tight">
<label for="pay-card-number">Card number</label>
<input
id="pay-card-number"
type="text"
class="input"
required
placeholder="1234 5678 9012 3456"
inputmode="numeric"
autocomplete="cc-number"
/>
</div>
<div class="grid" style="--grid-min: 8rem">
<div class="stack is-tight">
<label for="pay-expiry">Expiry</label>
<input
id="pay-expiry"
type="text"
class="input"
required
placeholder="MM / YY"
autocomplete="cc-exp"
/>
</div>
<div class="stack is-tight">
<label for="pay-cvc">CVC</label>
<input
id="pay-cvc"
type="text"
class="input"
required
placeholder="123"
inputmode="numeric"
autocomplete="cc-csc"
/>
</div>
</div>
<div class="stack is-tight">
<label for="pay-name">Cardholder name</label>
<input
id="pay-name"
type="text"
class="input"
required
autocomplete="cc-name"
/>
</div>
<label class="cluster is-tight">
<input type="checkbox" name="save-card" class="input" />
Save card for future purchases
</label>
<div class="cluster is-end">
<button class="button is-ghost" type="button">Back</button>
<button class="button" type="submit">Review order</button>
</div>
</form>
</div>
</div>
Order summary
Line items, then totals between dividers, so the amount to pay is the last thing before the button. The place-order button runs the full width; there is no second action.
Order summary
<div class="card center" style="--center-max: 40rem">
<div class="flow">
<h2>Order summary</h2>
<form class="stack">
<div class="stack is-tight">
<div class="cluster is-between">
<span>Widget <span class="text-muted">× 2</span></span>
<span>$24.00</span>
</div>
<div class="cluster is-between">
<span>Gadget <span class="text-muted">× 1</span></span>
<span>$15.00</span>
</div>
<div class="cluster is-between">
<span>Book <span class="text-muted">× 3</span></span>
<span>$39.00</span>
</div>
</div>
<hr class="divider is-tight" />
<div class="stack is-tight">
<div class="cluster is-between">
<span class="text-muted">Subtotal</span>
<span>$78.00</span>
</div>
<div class="cluster is-between">
<span class="text-muted">Shipping</span>
<span>$5.00</span>
</div>
<div class="cluster is-between">
<span class="text-muted">Tax</span>
<span>$6.64</span>
</div>
</div>
<hr class="divider is-tight" />
<div class="cluster is-between">
<strong>Total</strong>
<strong>$89.64</strong>
</div>
<button class="button is-block" type="submit">Place order</button>
</form>
</div>
</div>