Library Guide

CustomTkinter

Modern, rounded widgets with built-in dark mode โ€” the easiest way to upgrade tkinter's look.

Modern look Built on tkinter

What Is CustomTkinter?

CustomTkinter is a third-party Python library that wraps and extends standard tkinter with modern, fully custom-drawn widgets. Created by Tom Schimansky, it solves tkinter's biggest weakness โ€” appearance โ€” without forcing you to learn a new framework. Under the hood it still uses tkinter's event loop and window management; only the visual layer is replaced.

Widgets are rounded, anti-aliased, and support light mode, dark mode, and system mode (follows OS preference). Color themes (blue, green, dark-blue) can be switched globally with one function call.

Architecture & Core Concepts

  • CTk replaces Tk() as the root window.
  • Widget names mirror tkinter: CTkButton, CTkEntry, CTkLabel, CTkFrame, CTkScrollableFrame.
  • CTkTabview provides tabbed layouts; CTkOptionMenu and CTkComboBox handle selections.
  • Layout still uses pack(), grid(), or place() โ€” same rules as tkinter.
  • You can mix standard tkinter widgets in the same app if needed, though styling will differ.

Installation

shell
pip install customtkinter

# Requires tkinter (bundled on Windows/macOS)
python -c "import customtkinter; print(customtkinter.__version__)"

Example 1 โ€” Dark-mode app

python
import customtkinter as ctk

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

app = ctk.CTk()
app.title("CustomTkinter demo")
app.geometry("360x180")

ctk.CTkLabel(app, text="Modern UI in minutes").pack(pady=16)
ctk.CTkButton(app, text="Click", command=lambda: print("clicked")).pack()
app.mainloop()

Example 2 โ€” Login form with grid layout

python
import customtkinter as ctk

ctk.set_appearance_mode("system")
app = ctk.CTk()
app.title("Login")
app.geometry("340x220")

frame = ctk.CTkFrame(app)
frame.pack(padx=20, pady=20, fill="both", expand=True)

ctk.CTkLabel(frame, text="Username").grid(row=0, column=0, padx=10, pady=8)
user = ctk.CTkEntry(frame, placeholder_text="Enter username")
user.grid(row=0, column=1, padx=10)

ctk.CTkLabel(frame, text="Password").grid(row=1, column=0, padx=10)
pwd = ctk.CTkEntry(frame, show="*", placeholder_text="Enter password")
pwd.grid(row=1, column=1, padx=10)

def login():
    print(user.get(), pwd.get())

ctk.CTkButton(frame, text="Sign in", command=login).grid(row=2, column=1, pady=14, sticky="e")
app.mainloop()

Example 3 โ€” Tabbed settings panel

python
import customtkinter as ctk

app = ctk.CTk()
tabs = ctk.CTkTabview(app)
tabs.pack(padx=20, pady=20, fill="both", expand=True)
tabs.add("General")
tabs.add("Advanced")

ctk.CTkSwitch(tabs.tab("General"), text="Enable notifications").pack(pady=10)
ctk.CTkSlider(tabs.tab("Advanced"), from_=0, to=100).pack(pady=10)
app.mainloop()

Practical advice

  • Call set_appearance_mode() and set_default_color_theme() before creating widgets.
  • Use CTkScrollableFrame for long forms instead of nesting many widgets.
  • CustomTkinter handles HiDPI scaling better than raw tkinter on most systems.
  • For icons and images, use CTkImage (not plain PhotoImage) for sharp rendering.
  • When packaging with PyInstaller, include customtkinter as a hidden import if auto-detection fails.

Real-world use cases

  • Modern-looking desktop tools without learning Qt
  • Dashboards and monitoring panels with dark theme
  • Student projects that need polish with minimal effort
  • Migrating existing tkinter apps to a contemporary look

โœ“ Strengths

  • Beautiful out of the box; dark mode built in
  • Same mental model as tkinter
  • HiDPI aware, smooth widgets
  • Active development and community

โœ— Weaknesses

  • Smaller widget set than full toolkits
  • Still inherits tkinter's limits for complex apps
  • Extra dependency to package
  • Custom-drawn look is uniform, not OS-native
Use it when

You want a polished, modern-looking desktop app quickly without learning a heavyweight framework. Pair with standard tkinter for anything CustomTkinter doesn't cover (e.g. complex Treeview tables).