# VOLT: a free, open-source padel & squash club booking template

> A free, MIT-licensed padel & squash club booking template on Next.js 15 — court grid, coach-led training, Stripe checkout, player accounts. Deploy your own.

URL: https://opencals.com/blog/templates/volt
Author: Stanislav Tyshchenko
Published: 2026-09-20
Updated: 2026-09-20
Categories: engineering, announcement

Most padel clubs I look at have the same website: a decent-looking homepage, a photo gallery, opening hours, and a button that says **Book on Playtomic**. Click it and you leave the club's site entirely. The club spent money on a brand and then handed the only page that makes money to someone else's app.

**VOLT** is the alternative, and it's free. It's a complete padel and squash club website — court booking grid, coach-led training, checkout, player accounts — that you deploy on your own domain and own outright. The code is MIT licensed and lives on [GitHub](https://github.com/letsopencals/template-volt). The booking engine behind it runs on Opencals, so you're not writing an availability solver or handling card payments yourself.

![VOLT homepage hero — "Own the court" over a floodlit padel court, with 17 pro courts and a next-free-court chip](https://media.opencals.com/seo-content/inline/1789896823020-volt-homepage-hero.png)

The demo club is a fictional seventeen-court venue in Madrid with four coaches. Every name, price and photo in it is config you replace.

> **Key takeaway**
>
> VOLT is a frontend you own (MIT-licensed Next.js 15) on top of a backend you don't have to run (the Opencals Storefront API). Two booking surfaces over one store: a court grid for rentals, a coach-led flow for lessons. Live demo at [template-volt.vercel.app](https://template-volt.vercel.app).

## A court is not an appointment

This is the part that made VOLT worth building rather than restyling an existing template.

An appointment has a person attached. You pick a stylist, a dentist, a physio, and the system checks that human's calendar. Almost every booking tool on the market is shaped around that assumption, which is why so many of them handle courts badly — you end up faking a "staff member" called Court 4 and hoping nothing downstream notices.

A court has no person. It's an independent unit that one group occupies exclusively for a stretch of time, and booking Court 4 at 18:00 should leave Courts 1 through 17 completely untouched. In Opencals terms that's the **Self** rule with `maxAttendees: 1` — a staffless resource. Trainings in the same store use the **Staff** rule and carry group capacity, which is where the "4 left" counters come from.

The useful consequence is that order and appointment records read correctly either way. A rental comes through as _Padel Court 3 — 90 min_. A class comes through as _Intermediate Group — with Coach Marta_. Nobody has to decode a phantom staff member later.

## Seventeen courts on one grid

The court page is the centrepiece and it got most of the design budget.

One grid shows every court and every open slot for a day at once. Courts run down the left, time runs across the top, and you flip a Padel / Squash toggle to change which courts fill the rows. There's no service picker in front of it, no wizard, no "step 1 of 4" — you look at the grid and you can see immediately that Tuesday at 19:00 is gone and 20:30 is wide open.

![The VOLT court grid — eleven courts down the left, the afternoon across the top, and a duration popover pricing 30, 60, 90 and 120 minutes on Court 3](https://media.opencals.com/seo-content/inline/1789896823874-volt-book-a-court.png)

Tapping an open cell opens a duration popover on the spot. Hovering a duration highlights the cells it would span on the grid behind it, so you can see what you're about to take before you commit, and a Confirm button is the only thing that actually books. I went back and forth on that: the first version redirected straight to checkout on a single tap, which felt fast until I mis-tapped a cell on a phone and ended up two screens deep in a booking I didn't want.

## Where the thirty-minute steps get awkward

Courts in the demo sell in 30-minute steps up to two hours. That sounds like a non-problem and it's the bit that took the longest.

The API gives you slots. What a player wants is a duration. So the grid has to walk each court's row, find runs of consecutive free slots, and compose those into the 30 / 60 / 90 / 120-minute options that are genuinely available from the cell you tapped — then price each one. On Court 3 in the demo that's €15, €30, €45 and €60, and if the court is booked at 19:30 the 90- and 120-minute options simply don't appear for an 18:30 start.

That logic lives in a `use-court-grid` hook rather than in the page, which is deliberate: it's the piece most people will want to change. Clubs price peak hours differently, cap weekend rentals at 60 minutes, or sell 45-minute squash slots. All of that is one hook, not a rewrite.

## Coaching needed its own flow, not a variant

The first attempt tried to run lessons through the same grid. It was bad. A player booking a court is scanning for a gap; a player booking a lesson is choosing a coach and a level, and the grid gives them none of that.

So training is a separate surface over the same store. You filter the catalog by sport, format (1-on-1 or group) and level, then book through a classic card-stack: option, coach, date, time, details, payment.

![The VOLT training catalog, filtered by sport, format and level, showing padel lessons and group classes with prices](https://media.opencals.com/seo-content/inline/1789896824839-volt-training-catalog.png)

Two things in that flow matter more than they look.

**"Any coach" comes first.** The coach picker leads with _Any coach — next available_, ahead of the named ones. A beginner booking their first padel lesson has no opinion about whether they get Diego or Lena, and making them form one is a quiet way to lose the booking.

**Group classes show live capacity.** A group class is a [group service](https://opencals.com/features/group-appointments) with `maxAttendees` above one, so every slot carries a real "4 left" count that drops as people book and disappears when it fills.

![Training booking — level options, an "Any coach" card beside three named coaches, a date strip and morning slots each showing 4 left](https://media.opencals.com/seo-content/inline/1789896824391-volt-training-booking.png)

Checkout runs on Stripe Elements with [add-ons](https://opencals.com/blog/booking-add-ons) — racket and ball rental in the demo — and [custom questions](https://opencals.com/features/checkout-questions) you configure in the dashboard rather than in the template. Sign-in is passwordless by default: a six-digit code by email, with a password fallback. Every link Opencals emails a player afterwards resolves through a `/link/[token]` route that signs them in and drops them on the right page.

## An evening, and what that actually bought

VOLT went from nothing to the site in these screenshots in one evening. I want to be precise about why, because "we built a booking site in an evening" is the kind of claim that's useless without its conditions.

Three things already existed. The [Storefront SDK](https://opencals.com/blog/booking-sdk) was at v0.3.14 and typed, so availability, cart, checkout and accounts were calls rather than problems. Three templates had already been built on it — [Haar](https://opencals.com/blog/templates/haar) for a salon, [Frisor](https://opencals.com/blog/templates/frisor) for a barbershop, [Clarity](https://opencals.com/blog/templates/clarity) for a clinic — so the account pages, auth routes and checkout steps were patterns I'd already argued with. And a seeded demo store meant there were real courts, coaches, prices and photos to build against from the first minute.

What actually took the evening was the court grid, the duration composition, and the dark technical look. The rest was assembly.

The stack is deliberately dull so it's easy to read:

| Layer        | What it uses                                  |
| ------------ | --------------------------------------------- |
| Framework    | Next.js 15 (App Router)                       |
| Styling      | Tailwind CSS v4, design tokens in globals.css |
| Animation    | Framer Motion                                 |
| Forms        | react-hook-form + Zod                         |
| Payments     | Stripe Elements                               |
| Auth         | NextAuth.js v5, passwordless by default       |
| Dates        | moment-timezone                               |
| Booking data | Opencals Storefront SDK v0.3.14               |

Per-page metadata, Open Graph cards, `SportsActivityLocation` structured data, `robots.txt` and `sitemap.xml` ship configured, which is the week of SEO plumbing every club site otherwise pays for.

## What it won't do

Four limits, stated plainly, because you'll hit them in week one otherwise.

**No waitlist.** If Tuesday 19:00 is full, the grid shows it as booked and that's the end of the interaction. For a club, 19:00 on a Tuesday is exactly the slot you'd want a waitlist on. It's the gap I'd most like to close.

**No player matching.** Playtomic's real product is a network of players who find each other — open matches, levels, results. VOLT has none of that, and neither does Opencals. If your members book because the app finds them a fourth, a template won't replace it.

**Opencals itself is not open source.** VOLT is MIT and so is the SDK. The platform behind them is a commercial hosted product with a public API, and the engine isn't going to be open-sourced. Clone the frontend freely; the backend is a service you pay for — $14.98/month covering 300 bookings and $0.20 each after that, which is the plan a club doing court volume wants.

**The free tier can't take real money.** A Dev Store runs in test mode. It's there so you can build and demo the whole thing end to end without a card, and you move to a live store when you want real bookings.

## Playtomic solves a different problem

Worth saying clearly, because VOLT's grid is openly modelled on the one padel players already know: Playtomic is good at what it does, and what it does is run a marketplace. Its own [pricing page](https://playtomic.com/pricing) lists four club tiers — Standard, Professional, Champion and Master — with no published prices on any of them, and API integrations only appear from the Champion tier upward (checked 20 September 2026). Players booking through the app pay Playtomic a service fee that [varies by country and currency](https://playerhelp.playtomic.com/hc/en-gb/articles/19831779272337-Service-Fee) and isn't refunded if they cancel.

If most of your bookings arrive from players discovering you inside that app, that's a real distribution channel and a template is not a substitute for it. If most of your bookings are your own members, who already know your name and are going through a third-party app to reach you, the trade looks different. I've [written that comparison out properly](https://opencals.com/blog/compare/playtomic) — including the arithmetic — rather than squeezing it in here.

## The parts you'll edit first

Two files carry almost all the club-specific work.

`lib/site-config.ts` holds every piece of copy — club name, tagline, the two sports and their price hints, hero text, coaches, gallery, stats, testimonials, FAQs, address, hours, footer and social links. Rebranding the site is editing that one file. The bookable data — courts, trainings, prices, availability — comes from your Opencals store, not from the repo.

`app/globals.css` holds the design tokens as Tailwind v4 `@theme` properties. Token names are stable on purpose, so components keep working when the values change:

```css
@theme {
  --color-bg: #0A0A0A;          /* near-black page background */
  --color-primary: #FF4A1C;     /* electric-orange accent */
  --font-display: 'JetBrains Mono', ui-monospace, monospace;
}
```

Swap the orange for your club's colour, change the display face, and the site follows. Keep that accent matched to your storefront primary colour in Opencals so the booking emails don't clash with the site. One nice touch if you have footage: drop a file at `public/videos/hero.mp4` and the homepage hero upgrades from a still to a looping video with no code change.

## Getting it onto your own domain

You don't need to clone anything locally to get a live site.

1. **Create a Dev Store and seed it**: Sign up at app.opencals.com, create a Dev Store, and choose the VOLT Padel & Squash preset when it asks for a dataset. That seeds the courts, coaches, training classes, add-ons and venue the template expects, so your site renders like the demo instead of empty.
2. **Generate a Storefront API key**: In your Opencals account settings, generate a Storefront API key. It starts with sfk\_ and is scoped to that one store.
3. **Deploy to Vercel**: Use the deploy button below. Vercel asks for OPENCALS\_API\_KEY and AUTH\_SECRET — paste the sfk\_ key and any random string. Add a Stripe publishable key when you want to take real payments.

[Deploy to Vercel](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fletsopencals%2Ftemplate-volt\&env=OPENCALS_API_KEY,AUTH_SECRET\&envDescription=API%20key%20from%20your%20Opencals%20dashboard%20and%20a%20random%20secret%20for%20auth\&project-name=volt\&repository-name=template-volt)

> **Do this on day one or your emails break**
>
> Set **Storefront Base URL** in your Opencals dashboard (Settings → API) to your deployed domain. Every player link — view booking, reschedule, cancel, leave feedback — is built as `{storefrontBaseUrl}/link/{token}`. Leave it pointing at localhost and those links go nowhere.

- [VOLT on GitHub](https://github.com/letsopencals/template-volt): The full source, MIT licensed. Clone it, fork it, or one-click deploy.
- [VOLT live demo](https://template-volt.vercel.app): The club site running end to end — open the grid and book a court.
- [Clarity — clinic template](https://opencals.com/blog/templates/clarity): The same SDK with department-first booking and medical intake.
- [Opencals for developers](https://opencals.com/developers): The Storefront API, SDK and templates for building custom booking sites.

If you run a club, the question VOLT is really asking is whether the page where your members spend money should be yours or someone else's. If you build for clubs, it's a working reference implementation of court booking on a [headless backend](https://opencals.com/blog/headless-booking-system) — and you can fork it into your own design system in an afternoon. Either way, it's on GitHub and it costs nothing to find out.

## Frequently asked questions

### Is the VOLT padel template really free?

Yes. The template is MIT licensed — fork it, rebrand it, ship it for a client, no per-site fee. It connects to Opencals for the booking backend, which is a paid hosted service: $14.98/month including 300 bookings, then $0.20 each. A club doing court volume wants that plan rather than the $0.99 pay-per-booking one, which is built for low-volume businesses. You can build and demo the whole site for free on a Dev Store first.

### Do I need a developer to run it?

Yes, realistically. VOLT is a Next.js codebase, not a site builder. If someone on your team can edit a config file and deploy to Vercel, you're fine. If nobody will touch code, a hosted Opencals booking page gets your club online faster — VOLT is for clubs and agencies that want to own the frontend.

### Can it handle both padel and squash courts?

Yes, and that's the default setup. The demo runs seventeen courts across two sports with a toggle on the booking grid that switches which courts fill the rows. Each sport has its own collection, price and court list in your Opencals store, so adding a third sport is a data change rather than a code change.

### How does court booking differ from appointment booking here?

Courts are staffless resources — the Self rule with maxAttendees of 1 — so each court is an independent unit booked exclusively, and reserving one leaves the rest free. Trainings use the Staff rule and are assigned to real coaches, with optional group capacity that drives the live 'spots left' counts. One store, two models.

### Can VOLT replace Playtomic for my club?

For taking bookings on your own site, yes — court grid, durations, coaching, payments and player accounts all work. For player discovery it can't: Playtomic's value is a network of players finding matches and opponents, and neither VOLT nor Opencals does matchmaking, levels or open matches. Plenty of clubs run both — their own site for members, the marketplace for reach. The full comparison is at /blog/compare/playtomic.

### Where do courts, coaches and availability come from?

From your Opencals store, through the Storefront API. Courts and classes are products, collections group them by sport, coaches are staff, and slots are computed server-side from schedules, durations and existing bookings. The template renders it; nothing about the catalogue is hardcoded in the repo.

### How is VOLT different from the other Opencals templates?

Same SDK, different vertical and design. Haar is a hair salon, Frisor a barbershop, Clarity a medical clinic — all service-and-staff shaped. VOLT is the first with a resource grid: staffless courts booked by duration, plus a second coach-led flow over the same store. If you're booking rooms, bays, lanes or studios rather than people, VOLT is the closest starting point.
