Skip to content

Social Schedule Calendar

Full-page FullCalendar block for scheduling social media posts and campaign events.

Open in

Content calendar

Plan and review scheduled social posts and campaign events.

6 scheduled1 drafts1 published9 total
pnpm dlx shadcn@latest add @woxcn/social-schedule-calendar

Install the block and import the theme overrides in your global CSS (FullCalendar v6 injects its base styles automatically):

npx shadcn@latest add https://woxcn-registry.woxware.io/r/social-schedule-calendar.json
app/globals.css
@import "@/styles/social-schedule-calendar.css";

Wire posts and onSavePost so Schedule post opens a built-in sheet and persists new/edited events. Optional onDeletePost enables delete from the event details sheet.

"use client";
import { useState } from "react";
import {
SocialScheduleCalendarPage,
formDataToScheduledPost,
type SocialPostFormData,
type SocialScheduledPost,
} from "@/components/blocks/social-schedule-calendar";
export default function CalendarRoute() {
const [posts, setPosts] = useState<SocialScheduledPost[]>([]);
const handleSave = async (data: SocialPostFormData, id?: string) => {
const next = formDataToScheduledPost(data, id);
setPosts((current) =>
id ? current.map((p) => (p.id === id ? next : p)) : [...current, next],
);
// await api.posts.upsert(next);
};
const handleDelete = async (id: string) => {
setPosts((current) => current.filter((p) => p.id !== id));
// await api.posts.delete(id);
};
return (
<SocialScheduleCalendarPage
posts={posts}
onSavePost={handleSave}
onDeletePost={handleDelete}
/>
);
}

Click any calendar event to view details. Use Edit or Delete when the corresponding handlers are provided.

Manage sheet visibility from the parent (e.g. open from another button elsewhere on the page):

const [open, setOpen] = useState(false);
<SocialScheduleCalendarPage
posts={posts}
scheduleSheetOpen={open}
onScheduleSheetOpenChange={setOpen}
onSavePost={handleSave}
/>
<SocialScheduleCalendarPage
posts={posts}
onSavePost={handleSave}
renderScheduleSheet={({ open, onClose, onSave, defaultValues, mode }) => (
<MyCustomPostForm
open={open}
onClose={onClose}
onSubmit={onSave}
defaultValues={defaultValues}
mode={mode}
/>
)}
/>
PropTypeDefaultDescription
postsSocialScheduledPost[]Required. Posts shown on the calendar
onSavePost(data, id?) => void | Promise<void>Persists create (id omitted) or edit (id set). Enables schedule sheet + Edit
onDeletePost(id) => void | Promise<void>Removes a post. Enables Delete on event details
onEventClick(post, arg) => voidFired when a calendar event is clicked
classNamestringRoot wrapper classes
pageTitlestring"Content calendar"Page heading
pageDescriptionstring(see component)Subtitle under the title
maxEventsPerDaynumber4Day-grid overflow limit before “+N more”
localeFullCalendar localeen-gbCalendar locale
initialView"dayGridMonth" | "timeGridWeek" | "timeGridDay" | "listWeek""dayGridMonth"Starting view
aspectRationumber1.6Calendar width/height ratio
slotMinTimestring"06:00:00"Earliest time in week/day views
slotMaxTimestring"23:00:00"Latest time in week/day views
slotDurationstring"00:30:00"Slot height in time views
editablebooleanfalseDrag-and-drop events
selectablebooleanfalseClick-drag to select slots
weekendsbooleantrueShow Saturday/Sunday
nowIndicatorbooleantrueCurrent-time line in time views
showScheduleButtonbooleantrueHeader Schedule post button
scheduleSheetOpenbooleanControlled open state for schedule sheet
onScheduleSheetOpenChange(open) => voidPair with scheduleSheetOpen
renderScheduleSheet(props) => ReactNodeReplace built-in schedule form

Maps form values to a SocialScheduledPost. Generates a UUID when id is omitted.

const post = formDataToScheduledPost(formData);
// { id: "…", title, start: "2026-05-23T09:00:00", end?, platform, status, … }
type SocialPlatform = "instagram" | "facebook" | "linkedin" | "x" | "tiktok";
type SocialPostStatus = "draft" | "scheduled" | "published" | "failed";
interface SocialScheduledPost {
id: string;
title: string;
start: string; // ISO datetime
end?: string;
platform: SocialPlatform;
status: SocialPostStatus;
caption?: string;
campaign?: string;
}
interface SocialPostFormData {
title: string;
date: string; // YYYY-MM-DD
startTime: string; // HH:mm
endTime?: string;
platform: SocialPlatform;
status: SocialPostStatus;
caption?: string;
campaign?: string;
}

Posts are color-coded by platform. Draft posts appear faded; failed posts use the destructive token.