DEV Community

Cover image for How to structure a clean booking flow in Next.js + Tailwind (without heavy UI libraries)
Panos
Panos

Posted on

How to structure a clean booking flow in Next.js + Tailwind (without heavy UI libraries)

Every freelance web developer knows this pain: A client asks for a "simple" scheduling page. Suddenly, you're deep in the trenches fighting with JavaScript Date objects, timezone conversions, and installing massive, bloated UI libraries just to render a basic calendar grid.

I used to rely on heavy third-party packages for this, but customizing them to fit a modern, minimal design (like a Link-in-Bio page) always felt like wrestling a bear.

Recently, I decided to build a custom 3-step booking flow strictly using Next.js and Tailwind CSS. Here is the architectural approach that finally worked for me without the bloat.

  1. The Multi-Step State Architecture
    Instead of dumping everything into one massive component, you need to isolate the state of your booking flow. I typically break it down into three distinct steps:

  2. Date Selection: The calendar grid.

  3. Time Selection: Available slots based on the chosen date.

  4. User Details: Name, email, and confirmation.

By keeping the state at a parent level, you can easily slide between these components:
`import { useState } from 'react';

export default function BookingFlow() {
const [step, setStep] = useState(1);
const [bookingData, setBookingData] = useState({
date: null,
time: null,
details: {}
});

const nextStep = () => setStep((prev) => prev + 1);

return (


{step === 1 && { setBookingData({...bookingData, date}); nextStep(); }} />}
{step === 2 && { setBookingData({...bookingData, time}); nextStep(); }} />}
{step === 3 && completeBooking(details)} />}

);
}`
  1. Ditching heavy UI libraries for Tailwind Grid You don't need a 2MB library to draw a calendar. CSS Grid + Tailwind makes this incredibly simple. A basic 7-column grid for the days of the week is all you need: ` {/* Day Headers */} {['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'].map(day => ( {day} ))}

    {/* Date Cells */}
    {daysInMonth.map(day => (
    key={day}
    className="p-2 rounded-lg hover:bg-black hover:text-white transition-colors"
    >
    {day}

    ))}

    `

    The Result: LinkSync
    I got so tired of rewriting this exact logic for different freelance clients that I finally packaged it into a clean, reusable boilerplate called LinkSync.

    It’s a minimal Link-in-Bio profile that expands seamlessly into this exact fast, responsive booking flow.

    πŸ”— You can play with the live demo here: https://linksync-demo.vercel.app/demo

    If you want to save yourself ~10 hours of setup time on your next client project, I'm currently selling the full source code. As a thank you to the dev community, I'm giving a 50% discount to the first 3 buyers:
    πŸ‘‰ https://nospaa.gumroad.com/l/fdoaub/FIRST3

    How do you usually handle complex date selections in your React apps? Let me know in the comments!

Top comments (0)