How to Build a Custom Checkout Progress Bar in Magento 2

Why You Need a Custom Checkout Progress Bar in Magento 2
Let’s be honest—nobody likes a confusing checkout process. If your customers feel lost or unsure about where they are in the checkout flow, they might abandon their cart. That’s where a custom checkout progress bar comes in handy. It visually guides shoppers through each step, reducing friction and increasing conversions.
Magento 2’s default checkout is solid, but sometimes you need a little extra flair to match your store’s branding or improve UX. In this guide, we’ll walk through how to build a custom checkout progress bar in Magento 2—step by step, with code examples.
Understanding the Default Magento 2 Checkout Flow
Before diving into customization, let’s quickly recap how Magento 2’s checkout works by default:
- Shipping – Customer enters shipping details.
- Review & Payments – Customer selects payment method and reviews order.
- Success Page – Order confirmation.
The default progress indicator is minimal, just showing the current step. We’ll enhance this with a dynamic, visually appealing progress bar.
Step 1: Create a Custom Module
First, we need a module to house our customizations. Here’s how to set one up:
app/code/Magefine/CheckoutProgressBar/
├── etc/
│ └── module.xml
├── registration.php
└── view/frontend/
└── layout/
└── checkout_index_index.xml
registration.php:
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Magefine_CheckoutProgressBar',
__DIR__
);
etc/module.xml:
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Magefine_CheckoutProgressBar" setup_version="1.0.0">
<sequence>
<module name="Magento_Checkout"/>
</sequence>
</module>
</config>
Step 2: Override the Checkout Layout
Next, we’ll modify the checkout layout to include our custom progress bar.
view/frontend/layout/checkout_index_index.xml:
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="Magento\Framework\View\Element\Template" name="custom.checkout.progress" template="Magefine_CheckoutProgressBar::progress.phtml" before="checkout.root"/>
</referenceContainer>
</body>
</page>
Step 3: Create the Progress Bar Template
Now, let’s build the actual progress bar HTML and styling.
view/frontend/templates/progress.phtml:
<div class="custom-progress-bar">
<ul>
<li class="step-shipping active"><span>Shipping</span></li>
<li class="step-review"><span>Review & Payment</span></li>
<li class="step-success"><span>Order Complete</span></li>
</ul>
</div>
Step 4: Add CSS Styling
To make it look polished, we’ll add some CSS. Create a new file:
view/frontend/web/css/source/_module.less:
.custom-progress-bar {
margin-bottom: 30px;
ul {
display: flex;
list-style: none;
padding: 0;
justify-content: space-between;
li {
flex: 1;
text-align: center;
position: relative;
padding: 10px 0;
color: #ccc;
font-weight: bold;
&::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: #eee;
}
&.active {
color: #1979c3;
&::before {
background: #1979c3;
}
}
span {
position: relative;
z-index: 1;
background: #fff;
padding: 0 10px;
}
}
}
}
Step 5: Add JavaScript to Update Progress Dynamically
We need to update the progress bar as the customer moves through checkout.
view/frontend/web/js/progress.js:
define([
'jquery',
'Magento_Checkout/js/model/step-navigator'
], function ($, stepNavigator) {
'use strict';
return function () {
stepNavigator.steps.subscribe(function (steps) {
steps.forEach(function (step) {
if (step.isVisible()) {
$('.custom-progress-bar li').removeClass('active');
$('.custom-progress-bar .step-' + step.code).addClass('active');
}
});
});
};
});
Now, include this JS in your layout:
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceBlock name="head.additional">
<block class="Magento\Framework\View\Element\Text" name="custom.progress.js">
<action method="setText">
<argument name="text" xsi:type="string"><![CDATA[<script type="text/x-magento-init">
{
"*": {
"Magefine_CheckoutProgressBar/js/progress": {}
}
}
</script>]]></argument>
</action>
</block>
</referenceBlock>
</body>
</page>
Step 6: Test & Deploy
After setting everything up, run these commands:
php bin/magento setup:upgrade
php bin/magento setup:static-content:deploy -f
php bin/magento cache:flush
Now, your custom checkout progress bar should be live! Navigate to the checkout page to see it in action.
Advanced Customizations
Want to take it further? Here are some ideas:
- Add Icons – Include visual indicators (like checkmarks) for completed steps.
- Mobile Optimization – Adjust the layout for smaller screens.
- Progress Percentage – Show a dynamic percentage completion.
Final Thoughts
A well-designed checkout progress bar can significantly improve your store’s user experience. By following this guide, you’ve learned how to build a custom one in Magento 2 from scratch. Need a ready-made solution? Check out Magefine’s extensions for optimized checkout enhancements!
Got questions? Drop them in the comments below!