Not affiliated with official shadcn/ui. Visit ui.shadcn.com for official docs.
Unlock this block—Get Pro at 60% offReact Dialog Block Content Scheduler
Content scheduler dialog with date and time picker, timezone selector, platform toggles, and preview of scheduled posts
Looking to implement shadcn/ui blocks?
Join our Discord community for help from other developers.
Schedule content like a pro. This React content scheduler dialog enables users to plan posts across multiple platforms with date and time selection, timezone awareness, platform-specific toggles, and scheduled content preview. Built with shadcn/ui Dialog, Calendar, Select, Switch, Button, and Badge components using Tailwind CSS, content creators schedule publications with cross-platform visibility and time zone accuracy. Date picker, time selector, platform toggles—perfect for social media management tools, blog publishing platforms, marketing automation apps, or any Next.js application where content scheduling drives consistent engagement.
"use client";import { useState } from "react";import { Calendar as CalendarIcon, Clock, Globe, Check, Twitter, Linkedin, Instagram, Facebook,} from "lucide-react";import { Button } from "@/components/ui/button";import { Badge } from "@/components/ui/badge";import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger,} from "@/components/ui/dialog";import { Label } from "@/components/ui/label";import { Switch } from "@/components/ui/switch";import { Calendar } from "@/components/ui/calendar";import { Popover, PopoverContent, PopoverTrigger,} from "@/components/ui/popover";import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from "@/components/ui/select";import { cn } from "@/lib/utils";type Platform = { id: string; name: string; icon: React.ElementType; enabled: boolean; color: string;};const timezones = [ { value: "America/New_York", label: "Eastern Time (ET)", offset: "-05:00" }, { value: "America/Chicago", label: "Central Time (CT)", offset: "-06:00" }, { value: "America/Denver", label: "Mountain Time (MT)", offset: "-07:00" }, { value: "America/Los_Angeles", label: "Pacific Time (PT)", offset: "-08:00" }, { value: "Europe/London", label: "London (GMT)", offset: "+00:00" }, { value: "Europe/Paris", label: "Paris (CET)", offset: "+01:00" }, { value: "Asia/Tokyo", label: "Tokyo (JST)", offset: "+09:00" },];const timeSlots = [ "06:00", "06:30", "07:00", "07:30", "08:00", "08:30", "09:00", "09:30", "10:00", "10:30", "11:00", "11:30", "12:00", "12:30", "13:00", "13:30", "14:00", "14:30", "15:00", "15:30", "16:00", "16:30", "17:00", "17:30", "18:00", "18:30", "19:00", "19:30", "20:00", "20:30", "21:00", "21:30",];const initialPlatforms: Platform[] = [ { id: "twitter", name: "Twitter", icon: Twitter, enabled: true, color: "text-sky-500" }, { id: "linkedin", name: "LinkedIn", icon: Linkedin, enabled: true, color: "text-blue-600" }, { id: "instagram", name: "Instagram", icon: Instagram, enabled: false, color: "text-pink-500" }, { id: "facebook", name: "Facebook", icon: Facebook, enabled: false, color: "text-blue-500" },];export const title = "React Dialog Block Content Scheduler";export default function DialogContentScheduler() { const [open, setOpen] = useState(false); const [saved, setSaved] = useState(false); const [selectedDate, setSelectedDate] = useState<Date | undefined>(new Date()); const [selectedTime, setSelectedTime] = useState("09:00"); const [timezone, setTimezone] = useState("America/New_York"); const [platforms, setPlatforms] = useState<Platform[]>(initialPlatforms); const [showCalendar, setShowCalendar] = useState(false); const handlePlatformToggle = (platformId: string) => { setPlatforms((prev) => prev.map((p) => p.id === platformId ? { ...p, enabled: !p.enabled } : p ) ); }; const handleSave = () => { console.log({ date: selectedDate, time: selectedTime, timezone, platforms: platforms.filter((p) => p.enabled).map((p) => p.id), }); setSaved(true); }; const handleClose = () => { setOpen(false); setTimeout(() => { setSaved(false); setSelectedDate(new Date()); setSelectedTime("09:00"); setTimezone("America/New_York"); setPlatforms(initialPlatforms); setShowCalendar(false); }, 200); }; const formatDate = (date: Date) => { return date.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric", }); }; const formatTime12h = (time: string) => { const [hours, minutes] = time.split(":"); const h = parseInt(hours); const ampm = h >= 12 ? "PM" : "AM"; const hour12 = h % 12 || 12; return `${hour12}:${minutes} ${ampm}`; }; const enabledPlatforms = platforms.filter((p) => p.enabled); const isValid = selectedDate && selectedTime && enabledPlatforms.length > 0; const getRelativeTime = () => { if (!selectedDate) return ""; const now = new Date(); const scheduled = new Date(selectedDate); const [hours, minutes] = selectedTime.split(":"); scheduled.setHours(parseInt(hours), parseInt(minutes), 0, 0); const diff = scheduled.getTime() - now.getTime(); if (diff < 0) return "in the past"; const days = Math.floor(diff / (1000 * 60 * 60 * 24)); const hrs = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)); if (days > 0) return `in ${days} day${days > 1 ? "s" : ""}`; if (hrs > 0) return `in ${hrs} hour${hrs > 1 ? "s" : ""}`; return "soon"; }; return ( <Dialog open={open} onOpenChange={setOpen}> <div className="flex min-h-[350px] items-center justify-center"> <DialogTrigger asChild> <Button variant="outline"> <CalendarIcon className="mr-2 h-4 w-4" /> Schedule Post </Button> </DialogTrigger> </div> <DialogContent className="sm:max-w-md"> {saved ? ( <> <DialogHeader className="text-center"> <div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-primary/10 mb-4"> <Check className="h-6 w-6 text-primary" /> </div> <DialogTitle>Post Scheduled</DialogTitle> <DialogDescription> Your post will be published on {selectedDate && formatDate(selectedDate)} at{" "} {formatTime12h(selectedTime)} to {enabledPlatforms.length} platform {enabledPlatforms.length > 1 ? "s" : ""}. </DialogDescription> </DialogHeader> <div className="flex justify-center gap-2 py-2"> {enabledPlatforms.map((platform) => ( <div key={platform.id} className="flex h-10 w-10 items-center justify-center rounded-full border bg-muted/50" > <platform.icon className={cn("h-5 w-5", platform.color)} /> </div> ))} </div> <DialogFooter> <Button onClick={handleClose} className="w-full"> Done </Button> </DialogFooter> </> ) : ( <> <DialogHeader> <DialogTitle className="flex items-center gap-2"> <CalendarIcon className="h-5 w-5" /> Schedule Post </DialogTitle> <DialogDescription> Choose when and where to publish your content. </DialogDescription> </DialogHeader> <div className="space-y-4 py-4"> <div className="grid grid-cols-2 gap-3"> <div className="space-y-2"> <Label>Date</Label> <Popover open={showCalendar} onOpenChange={setShowCalendar}> <PopoverTrigger asChild> <Button variant="outline" className="w-full justify-start text-left font-normal" > <CalendarIcon className="mr-2 h-4 w-4" /> {selectedDate ? formatDate(selectedDate) : "Pick date"} </Button> </PopoverTrigger> <PopoverContent className="w-auto p-0" align="start"> <Calendar mode="single" selected={selectedDate} onSelect={(date) => { setSelectedDate(date); setShowCalendar(false); }} disabled={(date) => date < new Date()} initialFocus /> </PopoverContent> </Popover> </div> <div className="space-y-2"> <Label>Time</Label> <Select value={selectedTime} onValueChange={setSelectedTime}> <SelectTrigger> <Clock className="mr-2 h-4 w-4 text-muted-foreground" /> <SelectValue /> </SelectTrigger> <SelectContent> {timeSlots.map((time) => ( <SelectItem key={time} value={time}> {formatTime12h(time)} </SelectItem> ))} </SelectContent> </Select> </div> </div> <div className="space-y-2"> <Label>Timezone</Label> <Select value={timezone} onValueChange={setTimezone}> <SelectTrigger> <Globe className="mr-2 h-4 w-4 text-muted-foreground" /> <SelectValue /> </SelectTrigger> <SelectContent> {timezones.map((tz) => ( <SelectItem key={tz.value} value={tz.value}> {tz.label} </SelectItem> ))} </SelectContent> </Select> </div> <div className="space-y-3"> <Label>Publish to</Label> <div className="space-y-2"> {platforms.map((platform) => ( <div key={platform.id} className={cn( "flex items-center justify-between p-3 rounded-lg border transition-colors", platform.enabled && "border-primary bg-primary/5" )} > <div className="flex items-center gap-3"> <platform.icon className={cn("h-5 w-5", platform.color)} /> <span className="font-medium text-sm">{platform.name}</span> </div> <Switch checked={platform.enabled} onCheckedChange={() => handlePlatformToggle(platform.id)} /> </div> ))} </div> </div> {isValid && ( <div className="flex items-center justify-between p-3 rounded-lg border bg-muted/30"> <div className="space-y-0.5"> <p className="text-sm font-medium"> {selectedDate && formatDate(selectedDate)} at {formatTime12h(selectedTime)} </p> <p className="text-xs text-muted-foreground"> {getRelativeTime()} • {enabledPlatforms.length} platform {enabledPlatforms.length > 1 ? "s" : ""} </p> </div> <div className="flex -space-x-1"> {enabledPlatforms.slice(0, 3).map((platform) => ( <div key={platform.id} className="flex h-6 w-6 items-center justify-center rounded-full border-2 border-background bg-muted" > <platform.icon className={cn("h-3 w-3", platform.color)} /> </div> ))} {enabledPlatforms.length > 3 && ( <div className="flex h-6 w-6 items-center justify-center rounded-full border-2 border-background bg-muted text-xs"> +{enabledPlatforms.length - 3} </div> )} </div> </div> )} </div> <DialogFooter className="gap-2 sm:gap-0"> <Button variant="outline" onClick={handleClose}> Cancel </Button> <Button onClick={handleSave} disabled={!isValid}> Schedule </Button> </DialogFooter> </> )} </DialogContent> </Dialog> );}Installation
npx shadcn@latest add https://www.shadcn.io/registry/dialog-content-scheduler.jsonnpx shadcn@latest add https://www.shadcn.io/registry/dialog-content-scheduler.jsonpnpm dlx shadcn@latest add https://www.shadcn.io/registry/dialog-content-scheduler.jsonbunx shadcn@latest add https://www.shadcn.io/registry/dialog-content-scheduler.jsonRelated blocks you will also like
React Dialog Block Schedule Meeting
Date time selection
React Dialog Block Notification Preferences
Toggle preferences
React Dialog Block Export Data
Options configuration
React Dialog Block Share Link
Content sharing
React Dialog Block Quick Note
Content capture
React Dialog Block Success Confirmation
Schedule confirmation
Questions you might have
React Dialog Block Contact Support
Contact support dialog with issue category selection, priority level, message input, file attachment, and ticket submission
React Dialog Block Cookie Consent
Cookie consent dialog with preference toggles for different cookie categories, save preferences and accept all buttons