Skip to main content

Command Palette

Search for a command to run...

Build a Modern Calendar App in Python Using CustomTkinter (Beginner-Friendly Guide)

- By Pratyush Mishra

Published
5 min read
Build a Modern Calendar App in Python Using CustomTkinter (Beginner-Friendly Guide)
P

Do you need help with programming? You are not the only one. In this channel, we tackle gradual programming topics and end the videos on cool projects you can work on for practice to improve your skills on that given topic, step by step. Join us as we use fun and practical projects to grow our programming skills.😊💻.

Watch Video Tutorial : https://youtu.be/-EUKmRxIrG8

If you're learning Python and want to build a real project that looks modern, clean, and actually useful—this tutorial is made for you.

In this article, we’ll build a beautiful calendar application using CustomTkinter, a modern UI framework that makes Python GUIs look fresh and professional.

By the end, you'll learn:

✔ How to create a GUI window
✔ How to build a calendar grid
✔ How to navigate months
✔ How to add events to specific dates
✔ How to highlight selected days & event days
✔ How to structure a full Python desktop app

Let’s get started.


🚀 Why CustomTkinter?

Tkinter is powerful but looks outdated by default.

CustomTkinter upgrades Tkinter with:

  • Modern colors & gradients

  • Rounded corners

  • Better typography

  • Dark mode support

  • Pre-built beautiful widgets

So if you want modern desktop apps — CustomTkinter is the way to go.


🔧 Project Features

Our Calendar App will include:

  • A dark modern UI

  • A full month-view calendar

  • Previous / Next month navigation

  • Today button

  • Event manager panel

  • Adding events to any date

  • Highlighting:

    • Today → Blue

    • Active date → Purple

    • Dates with events → Green

Perfect for beginners learning Python GUI development.


📦 Installing CustomTkinter

Before coding, install the library:

pip install customtkinter

That's all you need!


🧱 Full Calendar App Code (CustomTkinter)

Below is the complete code used in this project:

import customtkinter as ctk
from datetime import datetime, timedelta
import calendar

class ModernCalendarApp(ctk.CTk):
    def __init__(self):
        super().__init__()

        self.title("Modern Calendar")
        self.geometry("900x700")

        ctk.set_appearance_mode("dark")
        ctk.set_default_color_theme("blue")

        self.bg_primary = "#0f0f23"
        self.bg_secondary = "#1a1a2e"
        self.accent_purple = "#6d28d9"
        self.accent_pink = "#ec4899"
        self.accent_blue = "#3b82f6"
        self.card_bg = "#16213e"
        self.hover_color = "#7c3aed"

        self.current_date = datetime.now()
        self.selected_date = None
        self.events = {} 

        self.create_header()
        self.create_calendar_grid()
        self.create_event_panel()

        self.display_month()

    def create_header(self):
        header_frame = ctk.CTkFrame(self, fg_color="transparent")
        header_frame.pack(pady=20, padx=20, fill="x")

        self.prev_btn = ctk.CTkButton(
            header_frame,
            text="◀",
            width=50,
            font=("Arial", 20, "bold"),
            command=self.previous_month,
            fg_color=self.accent_purple,
            hover_color=self.hover_color,
            corner_radius=12
        )
        self.prev_btn.pack(side="left", padx=10)

        self.month_year_label = ctk.CTkLabel(
            header_frame,
            text="",
            font=("Arial", 28, "bold")
        )
        self.month_year_label.pack(side="left", expand=True)

        self.today_btn = ctk.CTkButton(
            header_frame,
            text="Today",
            width=100,
            font=("Arial", 14, "bold"),
            command=self.go_to_today,
            fg_color=self.accent_pink,
            hover_color="#db2777",
            corner_radius=12
        )
        self.today_btn.pack(side="left", padx=10)

        self.next_btn = ctk.CTkButton(
            header_frame,
            text="▶",
            width=50,
            font=("Arial", 20, "bold"),
            command=self.next_month,
            fg_color=self.accent_purple,
            hover_color=self.hover_color,
            corner_radius=12
        )
        self.next_btn.pack(side="left", padx=10)

    def create_calendar_grid(self):
        self.calendar_frame = ctk.CTkFrame(self, fg_color="transparent")
        self.calendar_frame.pack(pady=10, padx=20, fill="both", expand=True)

        days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]
        for col, day in enumerate(days):
            day_label = ctk.CTkLabel(
                self.calendar_frame,
                text=day,
                font=("Arial", 14, "bold"),
                text_color=self.accent_pink
            )
            day_label.grid(row=0, column=col, padx=5, pady=5, sticky="nsew")

        self.date_buttons = []
        for row in range(1, 7):
            week_buttons = []
            for col in range(7):
                btn = ctk.CTkButton(
                    self.calendar_frame,
                    text="",
                    width=100,
                    height=80,
                    font=("Arial", 16),
                    fg_color=self.card_bg,
                    hover_color=self.hover_color,
                    corner_radius=12
                )
                btn.grid(row=row, column=col, padx=5, pady=5, sticky="nsew")
                week_buttons.append(btn)
            self.date_buttons.append(week_buttons)

        for i in range(7):
            self.calendar_frame.grid_columnconfigure(i, weight=1)
        for i in range(7):
            self.calendar_frame.grid_rowconfigure(i, weight=1)

    def create_event_panel(self):
        event_frame = ctk.CTkFrame(self, corner_radius=15)
        event_frame.pack(pady=10, padx=20, fill="both", expand=True)

        title_label = ctk.CTkLabel(
            event_frame,
            text="Events",
            font=("Arial", 20, "bold")
        )
        title_label.pack(pady=15)

        self.selected_date_label = ctk.CTkLabel(
            event_frame,
            text="Select a date",
            font=("Arial", 14)
        )
        self.selected_date_label.pack(pady=5)

        self.event_entry = ctk.CTkEntry(
            event_frame,
            placeholder_text="Add new event...",
            font=("Arial", 14),
            height=40
        )
        self.event_entry.pack(pady=10, padx=20, fill="x")

        self.add_event_btn = ctk.CTkButton(
            event_frame,
            text="Add Event",
            font=("Arial", 14, "bold"),
            command=self.add_event,
            fg_color=self.accent_purple,
            hover_color=self.hover_color,
            height=40,
            corner_radius=12
        )
        self.add_event_btn.pack(pady=5, padx=20, fill="x")

        self.events_textbox = ctk.CTkTextbox(
            event_frame,
            font=("Arial", 13),
            wrap="word"
        )
        self.events_textbox.pack(pady=10, padx=20, fill="both", expand=True)

    def display_month(self):
        month_name = self.current_date.strftime("%B %Y")
        self.month_year_label.configure(text=month_name)

        year = self.current_date.year
        month = self.current_date.month
        cal = calendar.monthcalendar(year, month)

        today = datetime.now()

        for week_idx, week in enumerate(cal):
            for day_idx, day in enumerate(week):
                btn = self.date_buttons[week_idx][day_idx]
                if day == 0:
                    btn.configure(
                        text="",
                        state="disabled",
                        fg_color=self.bg_secondary
                    )
                else:
                    date_obj = datetime(year, month, day)
                    date_str = date_obj.strftime("%Y-%m-%d")

                    has_events = date_str in self.events and len(self.events[date_str]) > 0

                    if (day == today.day and month == today.month and year == today.year):
                        fg_color = self.accent_blue  
                    elif has_events:
                        fg_color = "#10b981"  
                    else:
                        fg_color = self.card_bg

                    btn.configure(
                        text=str(day),
                        state="normal",
                        fg_color=fg_color,
                        command=lambda d=date_obj: self.select_date(d)
                    )

    def select_date(self, date):
        self.selected_date = date
        date_str = date.strftime("%B %d, %Y")
        self.selected_date_label.configure(text=date_str)
        self.display_events()

    def add_event(self):
        if not self.selected_date:
            return

        event_text = self.event_entry.get().strip()
        if not event_text:
            return

        date_key = self.selected_date.strftime("%Y-%m-%d")
        if date_key not in self.events:
            self.events[date_key] = []

        self.events[date_key].append(event_text)
        self.event_entry.delete(0, "end")
        self.display_events()
        self.display_month()

    def display_events(self):
        self.events_textbox.delete("1.0", "end")

        if not self.selected_date:
            return

        date_key = self.selected_date.strftime("%Y-%m-%d")
        if date_key in self.events and self.events[date_key]:
            for idx, event in enumerate(self.events[date_key], 1):
                self.events_textbox.insert("end", f"• {event}\n\n")
        else:
            self.events_textbox.insert("end", "No events for this day.")

    def previous_month(self):
        if self.current_date.month == 1:
            self.current_date = self.current_date.replace(year=self.current_date.year - 1, month=12)
        else:
            self.current_date = self.current_date.replace(month=self.current_date.month - 1)
        self.display_month()

    def next_month(self):
        if self.current_date.month == 12:
            self.current_date = self.current_date.replace(year=self.current_date.year + 1, month=1)
        else:
            self.current_date = self.current_date.replace(month=self.current_date.month + 1)
        self.display_month()

    def go_to_today(self):
        self.current_date = datetime.now()
        self.display_month()

if __name__ == "__main__":
    app = ModernCalendarApp()
    app.mainloop()

🧠 How the App Works (Beginner Explanation)

1️⃣ Window Setup

We create a window, set its size, choose dark mode, and define colors.

2️⃣ Calendar Grid

  • 7 columns (days)

  • Up to 6 rows (weeks)

  • Buttons represent each date

  • Buttons change color based on:

    • Today

    • Events

    • Regular days

3️⃣ Month Navigation

We calculate:

  • Previous month

  • Next month
    Using replace() on a datetime object.

4️⃣ Event System

We store events using:

self.events = { "2025-01-14": ["Doctor Appointment", "Meeting"] }

Each day can have multiple events.

5️⃣ Displaying Events

Selected date → Show event list
If no events → Show “No events for this day.”


🎉 Conclusion

You’ve built a fully functional calendar app in Python using a modern UI library—something beginners rarely attempt!

Skills you gained:

  • GUI development

  • Working with dates

  • Creating dynamic components

  • Event handling

  • Month calculations

If you want the next article to be:

✅ To-Do App
✅ Expense Tracker
✅ Password Manager
✅ Note-Taking App
Just tell me!