Skip to content

Accordion Checkout Steps

Each step is an accordion in the same group. Later steps start disabled until the previous one is completed, and open() moves the flow forward while earlier steps stay reachable for edits.

1 Shipping address
2 Delivery
3 Payment

Code

The following example assumes that you have imported the component and set up the theme.

Checkout Steps
<div class="checkout-steps">
52 collapsed lines
<sv-accordion group="checkout" opened>
<span slot="summary">
<span class="step-index">1</span>
Shipping address
</span>
<div class="fields">
<label>
Full name
<input type="text" autocomplete="off" />
</label>
<label>
Address
<input type="text" autocomplete="off" />
</label>
<button type="button" data-continue>Continue</button>
</div>
</sv-accordion>
<sv-accordion disabled group="checkout">
<span slot="summary">
<span class="step-index">2</span>
Delivery
</span>
<div class="fields">
<label class="option">
<input type="radio" checked name="delivery" />
Standard, 3 to 5 days
</label>
<label class="option">
<input type="radio" name="delivery" />
Express, next day
</label>
<button type="button" data-continue>Continue</button>
</div>
</sv-accordion>
<sv-accordion disabled group="checkout">
<span slot="summary">
<span class="step-index">3</span>
Payment
</span>
<div class="fields">
<label>
Card number
<input type="text" autocomplete="off" inputmode="numeric" />
</label>
<button type="button">Place order</button>
</div>
</sv-accordion>
</div>
<script type="application/x-typescript" module>
9 collapsed lines
const steps = [...document.querySelectorAll<Accordion>(".checkout-steps sv-accordion")];
for (const [index, step] of steps.entries()) {
step.querySelector("[data-continue]")?.addEventListener("click", () => {
step.classList.add("completed");
steps[index + 1].disabled = false;
steps[index + 1].open();
});
}
</script>
<style>
69 collapsed lines
.checkout-steps {
display: grid;
gap: 0.75em;
max-inline-size: 34rem;
padding-block: 1em;
margin-inline: auto;
[slot="summary"] {
display: flex;
gap: 0.6em;
align-items: center;
font-weight: 600;
}
.step-index {
display: inline-grid;
place-items: center;
inline-size: 1.6em;
block-size: 1.6em;
font-size: 0.85em;
background-color: var(--sv-gray-5);
border-radius: 50%;
}
.completed .step-index {
color: var(--sv-gray-7);
background-color: var(--sv-accent);
}
.fields {
display: grid;
gap: 0.75em;
justify-items: start;
padding-block: 0.25em 1em;
label {
display: grid;
gap: 0.3em;
inline-size: 100%;
font-size: 0.85em;
}
.option {
display: flex;
gap: 0.5em;
align-items: center;
font-size: 0.9em;
}
input[type="text"] {
padding: 0.5em 0.7em;
font: inherit;
color: var(--sv-gray-1);
background-color: var(--sv-gray-7);
border: 1px solid var(--sv-gray-5);
border-radius: var(--sv-bdr-rad-md);
}
button {
padding: 0.4em 1.2em;
font: inherit;
color: var(--sv-gray-7);
cursor: pointer;
background-color: var(--sv-accent);
border: none;
border-radius: var(--sv-bdr-rad-md);
}
}
}
</style>