Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Date Range Form Block for React

Two date inputs and a month that stay one range: booked nights drawn struck through and named when a block runs over one, an end before the start refused on the end field, and a two-night minimum.

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

Block a run of nights with this date range form for React with Base UI. A compact header sits over a hairline frame with a plus mark on each corner, in two cells. The first holds two Date Inputs, Start and End, and a summary ("5 nights, Fri 6 Nov to Wed 11 Nov"); the second is a month to pick from, drawn as a grid of buttons with a plus mark where it meets the first cell. The inputs and the month are one range: typing a date moves the highlight, and picking two days fills the inputs. Four nights are booked and drawn struck through; a range can't start on one, and one that runs over one says "Includes 14 Nov, which is booked" under the End field. The End is the morning the place opens again, so an End before the Start is refused on the End, and a block is at least two nights. It's built from Date Input, Button, Shine Button and Guides, with a CSS entrance only. For holiday lets, room blocks, leave and any form that takes a start and an end with rules between them.

FAQ

How do I change the booked nights, the minimum and the months?

Edit the constants at the top: BOOKED (ISO days), MIN_NIGHTS, MONTH_IDS (the months the grid can show) and AS_OF (the day the block treats as now, which closes the nights before it). startProblem and endProblem are the rules and return one sentence each; the fields, the summary and the Block dates check all read them, so a new rule is one more line there.

Why is the End a morning and not a night?

A booking is nights, and the last night is the one before the day you leave. So Fri 6 Nov to Wed 11 Nov is five nights (6, 7, 8, 9 and 10), and a booked night on the 11th does not block it. The month names this in words for a screen reader ("first night" on the Start, "the morning it opens again" on the End), and the check that finds a booked night looks at the nights only.

How do the inputs and the month stay in step?

There is one range, kept as two ISO days. The inputs report a date once all three segments are filled; a day picked on the month is written back into them through a small child component inside each input (DateBridge). The first pick starts a range, the second ends it, and picking a day on or before the Start starts again. The month is a grid of buttons and takes the arrow keys, one tab stop, and Enter or Space to pick.

When does it check, and where do the messages go?

When focus leaves the two fields, when you pick on the month and when you press Block dates, which also moves focus to the first field with a problem. A Start problem is under the Start, and everything about the End (before the Start, too short, over a booked night) is under the End, so each message sits next to the field you fix.

What stays local, and how do I connect it for real?

Nothing is blocked: Block dates says "5 nights blocked here only. Nothing was sent." To make it real, send the two ISO days from the submit handler, check the booked nights on your server too, and show its answer in the same status line. Feed BOOKED from your calendar rather than a constant.

How do I connect it to react-hook-form or TanStack Form?

Store the two ISO days as one value. With react-hook-form, use Controller, call field.onChange with the range from the inputs' value handlers and the month's pick handler, and put startProblem and endProblem in a resolver. With TanStack Form, validate the two fields together in a form-level onBlur.

  • Pro

    Leave Date Input Form

    Dates and times

    A date field you type or pick: month, day and year segments plus a calendar button, an impossible day named as it is typed, a soft year-end freeze notice, the date read back in words and two quick chips.

  • Pro

    An analytics page with a date-range dialog shown open: six presets worked out from a fixed day, a calendar for a custom range, start and end fields that check each other, a compare switch and a foot that counts the days.

  • Pro

    An equipment-hire request in four ruled bands: a tool select with its rates, an inline range calendar with a delivery switch, a band of hairline cells that prices the hire, then name and email.

  • Pro

    Loose Time Input Form

    Dates and times

    A pickup time field that accepts what people type, such as 9, 930, 9:30 pm or 21.30, reads it back in a 12 or 24 hour format and names the part of the rule a time breaks.

  • Pro

    Time Zone Select Form

    Dates and times

    A grouped select of sixteen time zones with the offset in each label, a real read of the device's own zone after the page loads, and one sentence saying how far the chosen zone is from it.

  • Pro

    Address Form with ZIP Help

    Checkout and address

    A six-column address grid that never changes size: street, an apartment line behind a quiet button, city, a state select and a ZIP code that fills the city and state from a typed table of six.