Steps, payment and summary with Tailwind
The Hyvä checkout is built from Alpine.js components with no Knockout.js and no UI components, styled entirely with Tailwind CSS utility classes. Knowing the right Hyvä checkout styling patterns for the step indicator, payment method selection and order summary helps you avoid layout shifts, unclear error states and inconsistent spacing between checkout steps.
Table of Contents
- 1. Why the Hyvä checkout needs its own styling mindset
- 2. Structure of the Hyvä checkout template
- 3. Step indicator: making progress visible
- 4. Payment method selection with peer and group
- 5. Address forms: validation and error states
- 6. Sticky order summary in the two column layout
- 7. Loading states and button feedback
- 8. Common mistakes in Hyvä checkout styling
- 9. Checkout styling patterns compared
- 10. Summary
- 11. FAQ
1. Why the Hyvä checkout needs its own styling mindset
The Hyvä checkout differs fundamentally from the Luma checkout: there is no Knockout.js binding, no UI components and no nested widget templates. Instead, Magento renders the checkout server side as phtml with Alpine.js components for interactivity and Tailwind CSS for the entire visual layer. This architecture means that Hyvä checkout styling is no longer about overriding Knockout templates, it is pure utility first work directly at the source.
Being this close to the source is an advantage, but it demands discipline. Without clear patterns for the step indicator, payment methods and order summary, inconsistent spacing between checkout sections quickly appears because every developer invents their own utility combinations. The following sections show proven Hyvä checkout styling patterns that have held up across multiple Magento projects and that can be implemented with Tailwind CSS without any extra JavaScript.
It also matters that the checkout is the most conversion critical area of the shop. Every visual uncertainty, for example an unclear error state in the address form, costs real orders. Clean Hyvä checkout styling measurably reduces abandonment because users can always tell which step they are on and whether an input was accepted.
2. Structure of the Hyvä checkout template
The Hyvä checkout lives in the hyva-themes/magento2-default-theme-csp module under Magento_Checkout/templates/onepage.phtml, plus several Alpine components in web/js/checkout. Every section, shipping, payment, order summary, is its own phtml block with a clearly scoped x-data Alpine component. For Hyvä checkout styling this means you override individual templates in your own theme instead of duplicating the entire checkout logic.
The base structure follows a two column layout on desktop and a stacked layout on mobile. The left area holds address, shipping and payment, the right area holds the order summary. This split is controlled purely through Tailwind grid classes, with no additional media query CSS files. Once you understand this structure, every single Hyvä checkout styling detail can be adjusted in isolation, without endangering the rest of the checkout.
<!-- app/design/frontend/Vendor/theme/Magento_Checkout/templates/onepage.phtml -->
<div x-data="initCheckout()" class="grid grid-cols-1 lg:grid-cols-[1fr_380px] gap-8 items-start">
<!-- Left column: address, shipping, payment steps -->
<div class="space-y-6">
<?= $block->getChildHtml('checkout.root') ?>
</div>
<!-- Right column: sticky order summary -->
<aside class="lg:sticky lg:top-6">
<?= $block->getChildHtml('sidebar') ?>
</aside>
</div>
3. Step indicator: making progress visible
An often underestimated detail in Hyvä checkout styling is the step indicator. Users need to see at all times which of the typically three steps, shipping, payment, confirmation, they are on. Tailwind does not ship a ready made component for this, but with flex, rounded-full and conditional classes bound through Alpine :class, a clear stepper can be built in a few lines.
The trick is to drive the active step from an Alpine variable and define the visual states, active, completed, pending, as three distinct class combinations. That keeps the whole stepper declarative in the template, without any JavaScript directly manipulating DOM classes. This pattern is reusable across any Hyvä checkout styling project, regardless of the number of steps.
<div x-data="{ step: 1 }" class="flex items-center gap-2 mb-8">
<template x-for="n in 3" :key="n">
<div class="flex items-center gap-2">
<span
class="w-8 h-8 rounded-full flex items-center justify-center text-sm font-bold"
:class="{
'bg-sky-600 text-white': step === n,
'bg-sky-100 text-sky-700': step > n,
'bg-slate-100 text-slate-400': step < n
}"
x-text="n"
></span>
<div class="w-8 h-0.5" :class="step > n ? 'bg-sky-600' : 'bg-slate-200'" x-show="n < 3"></div>
</div>
</template>
</div>
4. Payment method selection with peer and group
Payment method selection is where Tailwind's peer and group selectors show their full strength. Instead of writing a separate Alpine condition for every radio button, you couple the visual highlight of the selected payment card directly to the native :checked state of the hidden radio input. This is a core Hyvä checkout styling pattern, because it needs no additional JavaScript and stays fully CSS based.
The setup: an input type="radio" with the class peer and sr-only, followed by a label that changes background, border and text color through peer-checked: variants. For nested states, for example a disabled payment provider inside a group, group is used in addition. This combination makes Hyvä checkout styling for payment methods maintainable, because the entire state logic stays visible in the HTML instead of being scattered across JavaScript.
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<template x-for="method in paymentMethods" :key="method.code">
<div class="relative">
<input
type="radio"
:id="'payment-' + method.code"
name="payment-method"
class="peer sr-only"
x-model="selectedMethod"
:value="method.code"
>
<label
:for="'payment-' + method.code"
class="flex items-center gap-3 p-4 rounded-xl border-2 border-slate-200 cursor-pointer
peer-checked:border-sky-600 peer-checked:bg-sky-50
hover:border-slate-300 transition-colors"
>
<span class="w-5 h-5 rounded-full border-2 border-slate-300 peer-checked:border-sky-600"></span>
<span class="font-semibold text-sm" x-text="method.title"></span>
</label>
</div>
</template>
</div>
5. Address forms: validation and error states
Address forms are the longest and most error prone sections in the checkout. Solid Hyvä checkout styling for form fields needs three clearly distinguishable states: neutral, focused and errored. Tailwind covers focus states through focus:ring-2, error states can be driven through an Alpine bound :class object that reacts to the aria-invalid attribute.
It is important to never mark errors by color alone. A red bordered field by itself is not enough for users with color blindness. Alongside the border color there should be an icon and a text directly under the field, linked through aria-describedby. This detail is overlooked in many checkout implementations, but it is a mandatory part of accessible Hyvä checkout styling, because the checkout has to work for every user group.
6. Sticky order summary in the two column layout
On desktop screens the order summary stays visible on the right while the user scrolls through the steps on the left. The Hyvä checkout styling pattern for this is simple: lg:sticky lg:top-6 on the order summary container, combined with a max height and overflow-y-auto in case the cart holds many items. On mobile the sticky behaviour is disabled, since the summary already sits below the forms there.
An often missed detail: the sticky container needs a defined top value that matches the height of any sticky header present, see the separate sticky header templates in the theme. If the value does not match, the order summary overlaps the header while scrolling. For consistent Hyvä checkout styling it is worth defining this value as a CSS custom property, so header and checkout reference the same value.
7. Loading states and button feedback
The place order button is the single most important click target in the whole checkout. Without visible feedback during the asynchronous request, users click multiple times, which can lead to duplicate orders. A robust Hyvä checkout styling pattern disables the button immediately through :disabled, shows a spinner through x-show with animate-spin, and hides the original text without changing the button size.
Size stability is crucial: if the button changes width while loading, the layout beneath it jumps, which is especially disruptive on mobile. The solution is to position text and spinner on top of each other instead of rendering them sequentially, so the button stays exactly the same size regardless of state. This Hyvä checkout styling detail keeps the checkout feeling calm and professional while the order is submitted.
// Alpine.js component for the place-order button with stable size
function placeOrderButton() {
return {
isSubmitting: false,
async submit() {
this.isSubmitting = true;
try {
await this.$dispatch('checkout:submit-order');
} finally {
this.isSubmitting = false;
}
}
};
}
<button
x-data="placeOrderButton()"
@click="submit()"
:disabled="isSubmitting"
class="relative w-full bg-sky-600 text-white font-bold py-3 rounded-xl
disabled:opacity-70 disabled:cursor-not-allowed"
>
<span :class="{ 'invisible': isSubmitting }">Place order</span>
<span x-show="isSubmitting" class="absolute inset-0 flex items-center justify-center">
<svg class="animate-spin w-5 h-5" viewBox="0 0 24 24" fill="none">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z"></path>
</svg>
</span>
</button>
8. Common mistakes in Hyvä checkout styling
A common mistake is directly overriding the entire onepage.phtml when only a single section needs adjusting. That means core updates from Hyvä no longer flow in automatically, because the entire file has been duplicated in the custom theme. It is better to override only the specific child template that is actually affected and leave the rest of the structure untouched. That significantly reduces the maintenance burden for future Hyvä checkout styling work.
A second mistake is ignoring prefers-reduced-motion for transition animations between checkout steps. Some users enable this system setting for health reasons, and Tailwind respects it automatically through the motion-reduce variant when it is explicitly applied. Forget it, and the checkout feels unnecessarily busy for those users. A third common problem is inconsistent inner spacing between form sections, because every section uses its own p-4, p-6 or p-8 value instead of a shared spacing constant in the theme.
9. Checkout styling patterns compared
Not every styling problem in the checkout has just one solution. The table below shows which Hyvä checkout styling pattern is the more robust choice in which situation, compared to obvious but error prone alternatives.
| Requirement | Error prone | Recommended pattern | Benefit |
|---|---|---|---|
| Highlight payment method | Alpine condition per radio | peer-checked: variant |
No JS needed for pure styling |
| Pin order summary | position: fixed with custom CSS | lg:sticky lg:top-6 |
No overlap, no extra offset fix |
| Button while loading | Replace text with spinner | Spinner absolute over invisible text |
No width change, no layout shift |
| Copy entire onepage.phtml | Full file duplicated in theme | Override only the affected child template | Core updates stay usable |
Mironsoft
Hyvä theme development and Magento checkout optimization
A checkout that converts instead of scaring people off?
We design and optimize Hyvä checkouts with clean Tailwind patterns, clear error states and stable loading states, with no Knockout.js and no unnecessary JavaScript.
Checkout audit
Analysis of existing checkout templates for styling and accessibility gaps
Pattern library
Reusable Tailwind components for stepper, payment and summary
Conversion focus
Reduced abandonment through clear loading states and error messages
10. Summary
Thoughtful Hyvä checkout styling is built from a handful of consistently reused patterns instead of case by case fixes. The step indicator makes progress visible through Alpine bound :class states. Payment method selection uses peer-checked: for CSS based highlighting without any extra JavaScript. The order summary stays visible through lg:sticky lg:top-6, without overlapping the header. Loading states on the order button prevent double clicks and layout shifts through overlaid instead of sequential states.
Establishing these patterns consistently in your own theme not only reduces maintenance effort, it measurably improves conversion in the checkout. Every detail, from the focus ring color to the spinner, contributes to a feeling of control and trust that users need during the most sensitive phase of the purchase process.
Hyvä Checkout Styling Patterns — The Essentials at a Glance
Step indicator
An Alpine variable drives :class states for active, completed and pending, entirely declarative in the template.
Payment methods
peer-checked: variants tie the visual style directly to the native radio state, with no additional JavaScript.
Sticky summary
lg:sticky lg:top-6 with a matching offset to the sticky header prevents overlap while scrolling.
Loading states
Spinner positioned absolutely over invisible text, so button sizes stay stable during loading.