Skip to content

Segmented Control Billing Period

A pricing card where the period switch updates the price and submits with the form. The control is form-associated, so name puts the selected value straight into the FormData.

Pro plan

$12 per month

Billed every month

Code

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

Billing Period
<form class="billing-period">
15 collapsed lines
<div class="head">
<h3>Pro plan</h3>
<sv-segmented-control class="control" aria-label="Billing period" name="period" value="monthly">
<button value="monthly">Monthly</button>
<button value="yearly">Yearly</button>
</sv-segmented-control>
</div>
<p class="price">
<strong>$12</strong>
<span class="unit">per month</span>
</p>
<p class="note">Billed every month</p>
<button type="submit">Continue</button>
</form>
<script type="application/x-typescript" module>
18 collapsed lines
const form = document.querySelector<HTMLFormElement>(".billing-period")!;
const control = form.querySelector<SegmentedControl>(".control")!;
const price = form.querySelector(".price strong")!;
const unit = form.querySelector(".price .unit")!;
const note = form.querySelector(".note")!;
control.addEventListener("valuechange", () => {
const isYearly = control.value === "yearly";
price.textContent = isYearly ? "$120" : "$12";
unit.textContent = isYearly ? "per year" : "per month";
note.textContent = isYearly ? "Billed once a year, two months free" : "Billed every month";
});
form.addEventListener("submit", event => {
event.preventDefault();
note.textContent = `Continuing with the ${new FormData(form).get("period")} plan`;
});
</script>
<style>
60 collapsed lines
.billing-period {
max-inline-size: 24rem;
padding: 1.25em;
margin-inline: auto;
background-color: var(--sv-gray-7);
border: 1px solid var(--sv-gray-5);
border-radius: var(--sv-bdr-rad-lg);
.head {
display: flex;
flex-wrap: wrap;
gap: 1em;
align-items: center;
justify-content: space-between;
h3 {
margin: 0;
font-size: 1em;
}
.control {
flex-basis: 12em;
}
.control button {
font: inherit;
font-size: 0.9em;
}
}
.price {
margin: 0.75em 0 0;
strong {
font-size: 1.8em;
}
.unit {
color: var(--sv-gray-3);
}
}
.note {
margin: 0.25em 0 0;
font-size: 0.85em;
color: var(--sv-gray-3);
}
button[type="submit"] {
inline-size: 100%;
padding: 0.6em 1em;
margin-block-start: 1.25em;
font: inherit;
color: var(--sv-accent-content);
cursor: pointer;
background-color: var(--sv-accent);
border: none;
border-radius: var(--sv-bdr-rad-md);
}
}
</style>