Building Reusable, Mobile-First Step Components in Next.js for Multi-Step Forms
The Problem: Fragmented UX Across Devices
Multi-step forms are a necessary part of many web applications, but they’re also a common source of user friction—especially on mobile. At AustinsElite, we’d been rolling out several onboarding and booking flows built in Laravel 12, and despite their similar structure, each form had its own implementation of step indicators. Some used horizontal progress bars, others vertical lists. Some collapsed on mobile, others didn’t. The result? Inconsistent UX, duplicated code, and a maintenance headache.
We needed a single source of truth for step navigation—one that could adapt to different layouts, handle mobile gracefully, and support contextual help text without bloating the component API. So on August 19, 2024, we shipped a custom Step component that’s now being reused across multiple flows.
Designing a Flexible, Responsive Step Component
The goal was to build something reusable, not rigid. We wanted the same component to work in a horizontal progress tracker at the top of a desktop form and as a vertical list on mobile—without requiring separate implementations.
We started by defining two layout variants: horizontal and vertical. The default is horizontal, but the component accepts a layout prop to override this. The magic happens in CSS with a mobile-first approach using a single media query breakpoint at 768px. Below that, the component automatically switches to vertical mode unless explicitly locked.
const Step = ({
title,
subtitle,
isActive,
isCompleted,
layout = 'horizontal'
}) => {
const effectiveLayout = useMediaQuery('(max-width: 768px)') ? 'vertical' : layout;
return (
<div className={`step step--${effectiveLayout} ${isActive ? 'step--active' : ''}`}>
<div className="step__indicator">
{isCompleted ? <CheckIcon /> : <span className="step__number">1</span>}
</div>
<div className="step__content">
<h3 className="step__title">{title}</h3>
{subtitle && <p className="step__subtitle">{subtitle}</p>}
</div>
</div>
);
};
Notice the subtitle prop? That was a key addition. We realized users often needed extra guidance—like "Enter your full legal name" under "Personal Info"—so we baked in a dedicated slot for sub-text. It’s optional, but when used, it improves clarity without cluttering the design.
Styling leverages CSS Flexbox with conditional classes. On desktop, the horizontal layout uses a centered flex row with equal spacing. On mobile, it switches to a vertical stack with larger tap targets and clearer separation between steps. Accessibility was a priority: we used aria-current="step" for the active step and ensured focus states were visible.
Reusability That Actually Reduces Tech Debt
Before this component, every new form was copying and pasting step logic—with slight variations that snowballed into inconsistencies. One form used divs, another used ol/li. Some had subtext, others didn’t. Testing and QA became a game of "which version are we on?"
Now, we import Step from our shared UI library. Want a progress indicator? Wrap a list of Step components in a StepTracker. Need subtext? Pass subtitle. Switching layouts for mobile? Handled automatically.
The impact was immediate. In the week following the commit—'Added custom step with mobile break and sub-text'—we replaced three separate step implementations with the new component. Lines of code dropped by ~40% across those modules, and QA flagged zero layout bugs on mobile, a first for our form flows.
More importantly, it changed how we think about form design. Instead of asking "How do we build this flow?", we ask "How do we compose it from existing primitives?" That shift—from tactical coding to intentional component design—is where real scalability begins.
This was part of a broader August 2024 push to standardize reusable UI patterns in our Laravel 12 frontend, even as the primary AustinsElite production app runs on Laravel 12. The frontend layer, where user interaction lives, demands its own attention—and this step component is proof that small, focused investments in UI architecture pay dividends in consistency, speed, and user experience.