Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Date Range Picker Dialog Block for React

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.

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 choose the stretch of time a page describes, with this date-range dialog for React with Base UI. It opens from the Traffic page of Plotbridge, an analytics tool: the page is drawn, a rail, three figures and a line chart with its dates underneath, under a soft scrim inside a hairline frame with a plus mark on each corner, and its header holds an outline range button that says the range now set. The dialog has six presets, Today, Last 7 days, Last 30 days, This month, Last month and Last quarter, all worked out from one fixed day (9 Oct 2026), and a Custom one. A range Calendar shows the month and marks the days; start and end Inputs take the same range as year-month-day and check each other: the end can't come before the start, and nothing is after the fixed day. A Switch compares the range with the days just before it and writes that earlier range out. A line says the range in words and counts its days. Apply, the only Shine Button, writes the range to the page: the header button changes, and so do the dates under the chart and the line that is drawn from them. For preview the dialog is drawn open in place when the page loads; the header button opens the real Dialog, with the same choices and the same state. For analytics, reports, dashboards and any page that shows a period.

FAQ

Why is the dialog already open, and what do I keep?

So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The range button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same RangeFields component and share the block's state, so a range picked in the copy is there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.

Why is today fixed at 9 October 2026?

So the presets read the same for everyone and in every screenshot. AS_OF is the one day the block treats as now: Last 7 days ends on it, This month starts on the first of its month, and the calendar and the fields refuse anything later. The helpers work on ISO strings in UTC, so no time zone moves a day. In your app replace AS_OF with the current day, taken after mount so the server and the browser agree, and keep the presets as functions of it.

How do the calendar, the fields and the presets agree?

They all write the same two texts, the start and the end. Picking a preset sets both; a click on the calendar sets the start, and a second click sets the end; typing in a field sets its own, and the calendar follows once it is a real date. The chosen preset is the one whose dates match, and Custom takes over when they don't. Problems show after you leave a field or press Apply, in one reserved line: an empty or unreadable date, a date after the fixed day, or an end before the start.

What does compare do?

It takes the range's length in days and writes the same number of days just before the start: for 10 Sep to 9 Oct it says "Against 11 Aug to 9 Sep 2026". Applied, it draws the earlier period as a second, dashed line on the page behind. In your app ask your server for both periods and show the change between them next to each figure.

What stays local, and is the chart real?

The chart is drawn from the dates alone, a smooth line worked out from the day numbers, and no data is fetched. Apply changes local state and the page redraws from it. In your app replace lineOf with your series for the range, and send the two dates and the compare flag to your API in the apply handler.

Is it accessible from the keyboard?

Yes. The real dialog is named by its title and described by its sentence, focus stays inside until it closes, and Escape, Cancel and the close button return focus to the range button. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. The presets are one radio group you walk with the arrows, the calendar moves by day with the arrow keys, and the copy shown on load moves no focus; Escape inside it, Cancel and its close button close it and put focus on the range button.

  • Pro

    An analytics navbar for a product-analytics tool: scrolling report tabs, a date-range picker with presets and a calendar, and an Export action.

  • Pro

    A sprint board with a side sheet that assigns its one unowned task shown open: five people with their open tasks and load, a priority, a due date from chips or an inline calendar, and a switch to notify the assignee.

  • Pro

    Recurring Payment Dialog

    Payments and plans

    A rent page with its autopay dialog shown open: an amount, how often, a start day from a folded inline calendar, when it ends, and the next four payment dates worked out under the fields.

  • Pro

    Schedule Meeting Dialog

    Time and scheduling

    A month page with its new event dialog shown open: a title, a day from a folded calendar, a start time and length, guest emails as tags, and a day timeline that moves with the time and warns when the meeting clashes.

  • Pro

    Set Reminder Dialog

    Time and scheduling

    A to-do list with its reminder dialog shown open: five quick chips, an inline calendar and a time in quarter hours, repeat and notify choices, and one plain sentence that always reads the choice back.

  • Pro

    A vinyl shop's records page with its filter panel shown open as a sheet from the start edge: genre chips, a decade list, a two-thumb price range, conditions, an in-stock switch and a sort order, all changing the grid behind it as you touch them.