Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Sports Facilities Map Block for Radix UI

Eight sports sites on a drawn town with a multi-select sport filter; the chosen site's courts by hour are a grid of buttons where a free slot can be held, a taken one is dashed, and the pin shows the free count.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Let people see what is free before they walk there with this sports facilities map for React with Radix UI. Hoopfield, a network of sports centres, draws eight sites on a street map of an invented town. A multi-select ToggleGroup picks the sports, and the pins of the other sports go dashed. Each pin is a pill with the sport's code and the site's free slots for today, Monday 12 October. The chosen site's courts or lanes sit in a grid under the map, one row per court and one column per hour from 15:00 to 22:00: a free slot is a button that can be held, a taken one is dashed, aria-disabled and says "Taken". Holding a slot lowers the free count on the pin and in the list of sites, and the foot says what was held. The list of sites is the way in for the keyboard and the grid scrolls sideways on a phone. For sports centres, schools, leisure trusts and any bookable space.

FAQ

How are free and taken slots decided?

takenOf is a fixed rule over the site, the court and the hour, so the same slots are taken every time the block loads. Free is the grid's size minus the taken minus the ones you hold, and the pin, the site list and the grid all read it. In your app replace takenOf with your booking data for the date you show.

What does holding a slot do?

It marks the slot pressed, lowers the free count and says "Held Court 2 at 19:00, not booked." in the status line. Pressing it again releases it. Nothing is reserved anywhere and a reload clears every hold.

Can I use it without a mouse?

Yes. The sports are a toggle group, each site is a row button, and every slot is a button named with its court, hour and state ("Court 2, 19:00: free"). A taken slot stays in the tab order as a disabled button that says it is taken. The pins are hidden from assistive technology because the list says the same things.

What if no sport is chosen?

The site list shows an empty state, the slot grid says there is no site to show, and every pin goes dashed. The panel keeps its height, and choosing a sport brings the list back.

What stays local in the demo, and how do I wire it up?

All of it. Nobody can book a court here, the sites are invented and the date is a constant, AS_OF. In your app load the day's bookings per court, send a hold to your booking service, and treat the hold's expiry as the state to show.

How does it look on a phone?

The sports scroll sideways in one row, the map keeps a fixed height, the site list and the slot grid stack under it, and the grid scrolls sideways inside a focusable region so the first column stays readable.