diff --git a/src/pages/Schedule.jsx b/src/pages/Schedule.jsx
deleted file mode 100644
index 980b0e5bb47b8cef01e7094d47a3cdd2c503380f..0000000000000000000000000000000000000000
--- a/src/pages/Schedule.jsx
+++ /dev/null
@@ -1,7 +0,0 @@
-import React from "react";
-
-const Schedule = () => {
-  return <></>;
-};
-
-export default Schedule;
diff --git a/src/pages/SchedulePage.jsx b/src/pages/SchedulePage.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..12e03af3f889f9619d1faaf697f873242cfeb6d1
--- /dev/null
+++ b/src/pages/SchedulePage.jsx
@@ -0,0 +1,210 @@
+import React, { useState, useRef } from "react";
+
+const generateTimeSlots = () => {
+  const timeSlots = [];
+  for (let hour = 0; hour < 24; hour++) {
+    for (let min = 0; min < 60; min += 15) {
+      timeSlots.push(
+        `${hour.toString().padStart(2, "0")}:${min.toString().padStart(2, "0")}`
+      );
+    }
+  }
+  return timeSlots;
+};
+
+const days = ["월", "화", "수", "목", "금", "토", "일"];
+
+const SchedulePage = () => {
+  const timeSlots = generateTimeSlots();
+  const [schedules, setSchedules] = useState([]);
+  const isDragging = useRef(false);
+  const [draggedSlots, setDraggedSlots] = useState([]);
+  const [inputTitle, setInputTitle] = useState("");
+  const [isEditing, setIsEditing] = useState(false);
+  const [editMode, setEditMode] = useState(false);
+
+  const handleMouseDown = (slotIndex) => {
+    if (!editMode) return;
+    isDragging.current = true;
+
+    if (draggedSlots.includes(slotIndex)) {
+      setDraggedSlots((prev) => prev.filter((slot) => slot !== slotIndex));
+      return;
+    }
+
+    setDraggedSlots((prev) => [...new Set([...prev, slotIndex])]);
+
+    const schedule = schedules.find((s) => s.time_idx === slotIndex);
+    if (schedule) {
+      setInputTitle(schedule.title);
+      setIsEditing(true);
+    } else {
+      setInputTitle("");
+      setIsEditing(false);
+    }
+  };
+
+  const handleMouseEnter = (slotIndex) => {
+    if (!editMode || !isDragging.current) return;
+    setDraggedSlots((prev) => [...new Set([...prev, slotIndex])]);
+  };
+
+  const handleMouseUp = () => {
+    isDragging.current = false;
+  };
+
+  const handleMouseLeave = () => {
+    isDragging.current = false;
+  };
+
+  const handleSave = () => {
+    if (!inputTitle.trim()) return;
+
+    const newSchedules = [...schedules];
+    draggedSlots.forEach((slotIndex) => {
+      const existingIndex = newSchedules.findIndex(
+        (s) => s.time_idx === slotIndex
+      );
+      if (existingIndex === -1) {
+        newSchedules.push({
+          id: Date.now(),
+          time_idx: slotIndex,
+          title: inputTitle,
+          is_fixed: false,
+        });
+      } else {
+        newSchedules[existingIndex].title = inputTitle;
+      }
+    });
+
+    setSchedules(newSchedules);
+    setDraggedSlots([]);
+    setInputTitle("");
+    setIsEditing(false);
+  };
+
+  const handleDelete = () => {
+    const newSchedules = schedules.filter(
+      (s) => !draggedSlots.includes(s.time_idx)
+    );
+    setSchedules(newSchedules);
+    setDraggedSlots([]);
+    setInputTitle("");
+    setIsEditing(false);
+  };
+
+  return (
+    <div className="min-h-screen bg-gray-50">
+      {/* Edit Mode Toggle */}
+      <div className="flex items-center justify-between p-4 bg-white shadow">
+        <h1 className="text-lg font-bold mobile:text-base">Schedule</h1>
+        <label className="flex items-center space-x-3">
+          <span className="text-lg font-bold mobile:text-sm">Edit Mode</span>
+          <div
+            className={`relative w-12 h-6 rounded-full cursor-pointer transition-colors ${
+              editMode ? "bg-gradient-pink" : "bg-gray-300"
+            }`}
+            onClick={() => setEditMode((prev) => !prev)}
+          >
+            <div
+              className={`absolute top-0.5 left-0.5 h-5 w-5 rounded-full bg-white transition-transform ${
+                editMode ? "translate-x-6" : ""
+              }`}
+            ></div>
+          </div>
+        </label>
+      </div>
+
+      {/* Sticky Container (Edit Mode가 on일 때만 표시) */}
+      {editMode && (
+        <div className="sticky top-0 flex flex-col gap-2 p-4 bg-white shadow tablet:flex-row tablet:justify-between">
+          <input
+            type="text"
+            value={inputTitle}
+            onChange={(e) => setInputTitle(e.target.value)}
+            placeholder="Enter schedule title"
+            className="flex-1 p-2 border rounded"
+          />
+          <div className="flex space-x-2">
+            <button
+              onClick={handleSave}
+              className="flex-1 px-4 py-2 text-white rounded bg-gradient-pink disabled:opacity-50"
+              disabled={!draggedSlots.length}
+            >
+              {isEditing ? "Update" : "Save"}
+            </button>
+            <button
+              onClick={handleDelete}
+              className="flex-1 px-4 py-2 text-white rounded bg-gradient-purple disabled:opacity-50"
+              disabled={!draggedSlots.length}
+            >
+              Delete
+            </button>
+          </div>
+        </div>
+      )}
+
+      {/* Schedule Grid */}
+      <div className="p-4">
+        <div className="overflow-auto scrollbar-hide">
+          <div className="tablet:w-[960px] tablet:min-w-[800px] grid grid-cols-[64px,repeat(7,1fr)] gap-2">
+            {/* Header */}
+            <div className="min-w-[54px] p-2 font-bold text-center bg-gray-200 select-none">
+              Time
+            </div>
+            {days.map((day) => (
+              <div
+                key={day}
+                className="p-2 font-bold text-center bg-gray-200 select-none"
+              >
+                {day}
+              </div>
+            ))}
+
+            {/* Time Slots */}
+            {timeSlots.map((time, rowIndex) => (
+              <React.Fragment key={rowIndex}>
+                {/* Time Column */}
+                <div className="min-w-[54px] p-2 text-sm font-bold text-center bg-gray-100 select-none">
+                  {time}
+                </div>
+                {days.map((_, colIndex) => {
+                  const slotIndex = colIndex * timeSlots.length + rowIndex;
+                  const isSelected = draggedSlots.includes(slotIndex);
+                  const schedule = schedules.find(
+                    (s) => s.time_idx === slotIndex
+                  );
+
+                  return (
+                    <div
+                      key={slotIndex}
+                      className={`p-2 border rounded cursor-pointer ${
+                        editMode
+                          ? isSelected
+                            ? "bg-tertiary-300"
+                            : schedule
+                            ? "bg-primary-500 text-white"
+                            : "bg-white"
+                          : schedule
+                          ? "bg-primary-500 text-white"
+                          : "bg-gray-50"
+                      }`}
+                      onMouseDown={() => handleMouseDown(slotIndex)}
+                      onMouseEnter={() => handleMouseEnter(slotIndex)}
+                      onMouseUp={handleMouseUp}
+                      onMouseLeave={handleMouseLeave}
+                    >
+                      {schedule && !isSelected ? schedule.title : ""}
+                    </div>
+                  );
+                })}
+              </React.Fragment>
+            ))}
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default SchedulePage;