Skip to content
Drivn
5 min read

Drivn vs shadcn/ui — Time Picker Compared

Drivn ships a first-party Time Picker; shadcn/ui has none. Compare the scrolling column picker, 12h/24h formats, and the native input fallback side by side.

This comparison starts with the honest fact that frames everything below: shadcn/ui has no first-party Time Picker. Its registry ships a Date Picker built from Calendar plus Popover, but for time you are expected to compose your own from an Input type="time", a few Select dropdowns, or a community block. Drivn ships a dedicated Time Pickernpx drivn add time-picker drops a complete, scrolling column picker into your project. So this is not a feature-by-feature toss-up; it is a "Drivn gives you the component, shadcn gives you the parts" story.

Drivn's Time Picker lives at packages/drivn/src/registry/components/time-picker.ts. It is built on Drivn's own Popover and Input — no Radix, no cva, no date library — with every class in one const styles object. It gives you scrolling hour/minute/second columns that auto-center the selected value, a format prop for 12h or 24h, an optional seconds column, and a TimePicker.Input fallback that wraps the native <input type="time">. This page walks each capability with verbatim source from the Drivn registry, and is honest about where the shadcn compose-it-yourself approach is the better fit.

Side-by-side comparison

FeatureDrivnshadcn/ui
First-party Time PickerYes — dedicated componentNo — compose from Input/Select/Popover
Install commandnpx drivn add time-pickerNo registry item — build it yourself
Runtime UI dependenciesOwn Popover + Input — zero npm UI packagesRadix Popover/Select if you compose one
Clock formatformat prop — '12h' | '24h'Build the toggle yourself
Seconds columnshowSeconds propBuild the column yourself
Scroll-to-selectedYes — auto-centers on openBuild the scroll logic yourself
Native input fallbackTimePicker.Input — input type="time"Use a plain Input type="time"
Styling patternSingle const styles objectInline cn() per composed element
Value typeDate object via selected / onSelectWhatever your composition returns
LicenseMITMIT

shadcn has no first-party Time Picker

The starting point of any honest comparison: there is no npx shadcn add time-picker. shadcn/ui ships a Date Picker recipe — Calendar inside a Popover — but time selection is left to you. The shadcn docs and community point you at three routes: a native <input type="time"> styled with the Input classes, a row of Select dropdowns for hours and minutes, or a third-party block you paste in. All three work, but all three are assembly, not installation.

Drivn closes that gap with a single command. npx drivn add time-picker installs a complete component under @/components/ui/time-picker that you then own and can edit. It is built on Drivn's Popover and Input, so it pulls in no new dependency you did not already have. The result is the usual Drivn trade flipped in Drivn's favour here: instead of choosing and wiring parts, you get a working picker on first install and edit from there.

1import { TimePicker } from "@/components/ui/time-picker"
2
3const [time, setTime] = React.useState<Date | undefined>()
4
5<TimePicker
6 selected={time}
7 onSelect={setTime}
8/>

The scrolling column picker that auto-centers

The core of the Drivn Time Picker is its Column sub-component: a scrollable list of hour, minute, and (optionally) second values. The detail that makes it feel finished is the React.useEffect that scrolls the selected value into the centre of its column when the popover opens — it reads the [data-selected] element's offset and sets scrollTop so the active number sits mid-column rather than at the top. If you composed a time picker from shadcn Select dropdowns you would get a usable result, but not this scroll-to-selected behaviour without writing the same effect yourself.

Each cell is a button that pads its value with padStart(2, "0") and flips to the active styling — bg-foreground text-background — when it matches the current selection. This is verbatim from the Drivn registry; the whole column, scroll logic included, is a few lines you can read and re-style in place.

1// packages/drivn/src/registry/components/time-picker.ts — verbatim
2const ref = React.useRef<HTMLDivElement>(null)
3React.useEffect(() => {
4 const col = ref.current
5 const el = col?.querySelector('[data-selected]') as HTMLElement | null
6 if (!col || !el) return
7 col.scrollTop = el.offsetTop - col.offsetTop - col.clientHeight / 2 + el.clientHeight / 2
8}, [selected])

12h, 24h, and seconds from one prop each

Drivn's Time Picker handles the format permutations through props instead of separate components. The format prop takes '12h' or '24h' (default 24h); in 12h mode the root computes h12 = h % 12 || 12, derives the AM/PM period from h >= 12, and renders a period column with a to24 helper that maps the 12-hour value back to a 24-hour Date. The showSeconds prop adds a third scrolling column. The hours array itself is built inline from the format, so there is no branching component tree to maintain.

Reproducing this on a shadcn composition means wiring the 12h/24h toggle, the AM/PM state, and the seconds column by hand and keeping them in sync with a single Date. Drivn folds all of it into the one component you installed. The public API stays small — you flip a prop, not a sub-tree — which is the same defaults-driven approach you see across Drivn vs shadcn comparisons.

1// packages/drivn/src/registry/components/time-picker.ts — verbatim
2const is12 = format === '12h'
3const h = selected?.getHours()
4const period = h !== undefined ? (h >= 12 ? 'PM' : 'AM') : undefined
5const h12 = h !== undefined ? (h % 12 || 12) : undefined
6const hours = is12 ? Array.from({ length: 12 }, (_, i) => i + 1) : Array.from({ length: 24 }, (_, i) => i)

Where the shadcn approach wins: native input and simplicity

Being fair to the compose-it-yourself route: for many forms a plain <input type="time"> is genuinely enough, and that is the lightest possible answer — no popover, no columns, native mobile pickers for free. Drivn does not argue against this; it ships the same option as TimePicker.Input, a wrapper around the native time input that formats the Date to an HH:MM value string. If all you need is a quick time field on a settings page, the input fallback is the right call on either library.

The shadcn approach also wins when your design demands something the column picker is not — a stepper, a slot-machine wheel, fixed 15-minute intervals. Building from parts means you build exactly what the design asks for and nothing more. Drivn's answer is that you still own the installed source, so you can strip the columns down or swap the layout after install — but if your needs are far from a column picker, starting from shadcn primitives can be the shorter path.

1import { TimePicker } from "@/components/ui/time-picker"
2
3const [time, setTime] = React.useState<Date | undefined>()
4
5<TimePicker.Input
6 selected={time}
7 onSelect={setTime}
8/>
Get started

Install Drivn in one command

Copy the source into your project and own every line. Zero runtime dependencies, pure React + Tailwind.

npx drivn@latest create

Requires Node 18+. Works with npm, pnpm, and yarn.

Enjoying Drivn?
Star the repo on GitHub to follow new component releases.
Star →

Frequently asked questions

No. shadcn/ui ships a Date Picker recipe built from Calendar and Popover, but it has no first-party Time Picker in its registry. For time selection you compose your own from a native input type="time", a set of Select dropdowns, or a community block. Drivn, by contrast, ships a dedicated Time Picker you install with npx drivn add time-picker.

Drivn's Time Picker is built on its own Popover and Input components plus React and the cn() helper — no Radix, no cva, and no date library. The trigger uses a Clock icon from lucide-react, and the dropdown renders scrolling hour, minute, and optional second columns inside the Popover content. Everything is held in one const styles object you can edit after install.

Through the format prop, which takes "12h" or "24h" and defaults to "24h". In 12h mode the component computes h12 as h % 12 || 12, derives the AM/PM period from whether the hour is 12 or more, and shows an AM/PM column. A to24 helper converts the chosen 12-hour value back into a 24-hour Date so onSelect always receives a real Date object.

Yes. Pass the showSeconds prop and a third scrolling column appears for seconds, alongside the hours and minutes. The values column is built from Array.from({ length: 60 }), so it covers 0 through 59. Without the prop the picker shows only hours and minutes, which is the right default for most scheduling and form use cases.

Yes — TimePicker.Input wraps the native input type="time" inside Drivn's Input component. It formats the selected Date into an HH:MM string and parses changes back into a Date on onSelect. Use it when you want the lightweight native picker, including the built-in mobile time UI, instead of the scrolling column dropdown.

Because you get a working, scrolling column picker on first install instead of wiring Select dropdowns, AM/PM state, and scroll-to-selected logic yourself. Drivn still hands you the full source to edit, so you own it exactly as you would a shadcn composition. If your design needs something far from a column picker, composing from shadcn primitives can be shorter — but for a standard time field, Drivn is the faster route.