Library / SDK
TomSchimansky/CustomTkinter avatar
TomSchimansky/CustomTkinter

CustomTkinter wraps Tkinter, and Tk's layout rules still apply

A modern and customizable python UI-library based on Tkinter

13,614 stars1,165 forksPythonMIT

At a glance

What is it?
CustomTkinter restyles Tkinter with light, dark and system appearance modes, three built-in themes and HighDPI scaling on Windows and macOS, without changing how Tk lays out widgets or how versions are pinned.
Who is it for?
Adopt CustomTkinter when you have already chosen Tkinter and want dark mode, system mode and one widget skin across the three desktop platforms without touching your layout code. Do not adopt it if you need a documented per-widget theme API, documented Linux scaling, a map widget in the same install, or a supported way back from a bad upgrade.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • TomSchimansky/CustomTkinter13,614 ★ · +50
Star history
Repository2026-09-222026-11-14
TomSchimansky/CustomTkinter13.6k13.6k

50 Stars in the last 53 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

place, grid and pack still decide where every CTk widget lands

CustomTkinter keeps Tk's construction rules instead of replacing them. Class names map one to one onto their Tkinter counterparts, so CTk stands in for Tk and CTkButton is dropped in where a tkinter Button used to sit. Windows are built as customtkinter.CTk() and sized with app.geometry("400x240"), the same two calls a plain Tk program makes, and every CTk widget can sit beside normal Tkinter elements in one window. Positioning still goes through Tk's geometry managers, so a widget is placed with place, grid or pack exactly as before, and the library adds no layout layer of its own. No percentage columns, no gap rules, no container that reflows its children when the window changes size. The wiki the README links to covers the appearance mode, scaling, themes and the widget list, and layout stays where Tkinter left it.

Three theme names and three appearance modes are the whole config surface

Two module-level calls set the look for the whole process. customtkinter.set_appearance_mode("System") accepts system, which is the default, light and dark. customtkinter.set_default_color_theme("blue") accepts blue, dark-blue and green, with blue as the default. In the README example both run before the window object exists, which tells you they are process-wide settings rather than per-widget arguments, and that also marks the ceiling. No call is given in the README for registering a theme of your own, and anything the library does not wrap will not follow a mode switch. requirements.txt pins darkdetect~=0.7.0, the theme detection package behind system mode, plus typing-extensions~=4.4.0, packaging and setuptools. Nothing is said about what happens when detection returns nothing, so the fallback behaviour is not something the docs give you.

pip is the only install path, and no release page exists to pin from

One command installs the module:

bash
pip3 install customtkinter

Updating an existing install adds one flag, and the advice attached to it is to update often because the library is under active development:

bash
pip3 install customtkinter --upgrade

The last push to the repository was on 2026-06-24, and there are no GitHub releases, so no version number appears on a release page. The version lives in the source, and pyproject.toml keeps a copy for the tbump tool:

toml
[tool.tbump.version]
current = "6.0.0"

That tool is configured to patch setup.cfg and customtkinter/__init__.py as well, which means two files have to agree with the packaging metadata, and its regex is required to match the current version before it can bump anything. Alongside the package the repository carries .pre-commit-config.yaml, a test/ directory and dev-proces.md. What you do not get is a documented way to hold a version or go back to an earlier one, so an upgrade that alters a widget's height or padding leaves you reading CHANGELOG.md by hand to find out what moved.

The smallest complete program sets the two global options, builds the window and places a single button:

python
import customtkinter

customtkinter.set_appearance_mode("System")  # Modes: system (default), light, dark
customtkinter.set_default_color_theme("blue")  # Themes: blue (default), dark-blue, green

app = customtkinter.CTk()  # create CTk window like you do with the Tk window
app.geometry("400x240")

def button_function():
    print("button pressed")

# Use CTkButton instead of tkinter Button
button = customtkinter.CTkButton(master=app, text="CTkButton", command=button_function)
button.place(relx=0.5, rely=0.5, anchor=customtkinter.CENTER)

app.mainloop()

Run it and a 400x240 window opens with one centred button that prints button pressed on click. For a wider look at the widget set, the README gives a second entry point that opens every available widget in one window:

python
import customtkinter as ctk
ctk.run_showroom()

Use that window as your baseline before restyling anything, because it is the fastest way to see which widget a later change affected.

macOS dark window headers depend on which Python you run

On macOS, set_appearance_mode("dark") does not by itself hand you a dark window header. You either need python3.10 or higher or the anaconda python version, with Tcl/Tk >= 8.6.9 required. Widgets the library draws follow the mode you asked for; the chrome above them is painted by the Tcl/Tk build that shipped inside your interpreter, which is the whole reason the version floor exists. A developer running python3.9 with the system Tk therefore gets restyled widgets under a light title bar, and no flag in the documentation overrides that, since the documented remedy is a different interpreter. The same asymmetry bites Windows developers only in the other direction, where the README points at Windows 10 and 11 light or dark mode as something the library adapts to rather than something you configure. On Linux, window headers get no statement at all.

HighDPI scaling is claimed for Windows and macOS, not for Linux

One sentence says that all CustomTkinter widgets and windows support HighDPI scaling, and it names Windows and macOS. The sentence after it promises a consistent and modern look across all desktop platforms, Windows, macOS and Linux, with Linux absent from the scaling claim. That gap matters for a Linux packager, because nothing states how the scale factor is derived, whether a fractional factor such as 1.25 is honoured, or how to force a value when you capture screenshots at a fixed size. The README points to the wiki for scaling details and to an examples folder holding complex_example.py, scrollable_frame_example.py, image_example.py, example_background_image.py and simple_example.py, none of which is a scaling harness you can measure with. If your Linux users sit at 125 or 150 percent, that is the first thing you have to check yourself.

Button images arrive as Tk PhotoImage objects, and compound does the layout

Images on a button travel through Tk rather than through the library. You pass a PhotoImage object to the CTkButton with the image argument. If you want no text at all you set text="", or you set the compound option to say how the text and the image sit together. Two consequences follow for a designer. No other image type is documented, so a JPEG or a PNG loaded through a separate imaging library has no stated route into a CTkButton. And because compound hands the pair to Tk's own layout rules, text and image cannot be layered, nudged or overlapped the way a layout written in CSS would allow. The examples folder ships a test_images directory for image_example.py, which is the closest thing to a specification of what a button image is supposed to look like at each size.

Maps come from TkinterMapView, a second repository and a second install

The map widget people ask about is not part of this package. The README points at TkinterMapView, a tile based map widget that displays OpenStreetMap or other tile based maps, and says it integrates well with a CustomTkinter program. The example lives at examples/map_with_customtkinter.py inside the TkinterMapView repository, and the library comes from github.com/TomSchimansky/TkinterMapView. A CustomTkinter install therefore gives you no map, and any application that needs one carries a second dependency with its own version history. Nothing in the documentation describes pointing the widget at tiles you host yourself.

Plain Tkinter stays four dependencies lighter and lays out identically

tkinter ships with Python, so it is the honest baseline for this decision. CustomTkinter adds four requirements, darkdetect~=0.7.0, typing-extensions~=4.4.0, packaging and setuptools, and buys a light, dark or system mode, three named themes and one widget skin that looks the same on three desktop platforms, on top of geometry managers that behave exactly as Tk's do. The cost is a layer: each CTk class sits over a Tkinter widget, and since the two kinds can be combined in one program, anything the library does not wrap still has to come from tkinter primitives, which means two widget idiomes inside a single codebase. Qt toolkits such as PySide take the opposite approach and draw their own widgets, so they need no Tcl/Tk on the machine, at the price of a much larger runtime. The README names no alternative library and makes no comparison of its own.

Editorial conclusion

Adopt CustomTkinter when you have already chosen Tkinter and want dark mode, system mode and one widget skin across the three desktop platforms without touching your layout code. Do not adopt it if you need a documented per-widget theme API, documented Linux scaling, a map widget in the same install, or a supported way back from a bad upgrade. Before committing, install it with pip3 install customtkinter and run the example on the exact interpreter you will ship: python3.10 or the anaconda build on macOS for a dark header, over a Tcl/Tk of 8.6.9 or newer. The MIT licence adds no obligation beyond keeping the notice, and since the repository publishes no GitHub releases, CHANGELOG.md is where you verify what a version changed.

Frequently asked questions

Is CustomTkinter better than Tkinter?

It depends on which Tkinter limitation you are trying to remove. CustomTkinter keeps Tkinter's geometry managers and adds light, dark and system appearance modes plus blue, dark-blue and green themes, at the cost of four extra dependencies from requirements.txt.

How do I pip install CustomTkinter?

Run pip3 install customtkinter. To update an existing install the README gives pip3 install customtkinter --upgrade and recommends updating often because the library is under active development. The last push was on 2026-06-24 and the repository has no GitHub releases.

How do I use CustomTkinter in Python?

Import the module, call customtkinter.set_appearance_mode("System") and customtkinter.set_default_color_theme("blue"), create customtkinter.CTk() and substitute CTk classes such as CTkButton for their Tkinter equivalents. customtkinter as ctk followed by ctk.run_showroom() opens every available widget in one window.

How do I use grid in CustomTkinter?

CustomTkinter adds no layout manager of its own, so grid is Tkinter's grid used on a CTk parent. The README's own example places its button with place instead, calling button.place(relx=0.5, rely=0.5, anchor=customtkinter.CENTER).

How do I install CustomTkinter on a Mac?

The same pip3 install customtkinter command applies. On macOS you either need python3.10 or higher or the anaconda python version to get a dark window header, and Tcl/Tk >= 8.6.9 is required.

Does CustomTkinter work on a Raspberry Pi?

The README gives no Raspberry Pi specific steps and no platform matrix beyond naming Windows, macOS and Linux. HighDPI scaling is claimed for Windows and macOS only, so nothing states how a Raspberry Pi display is scaled.

Official sources

  1. Issues
  2. License: MIT
  3. README
  4. TomSchimansky/CustomTkinter on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/tomschimansky-customtkinter.svg)](https://hysenlabs.com/projects/tomschimansky-customtkinter)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/tomschimansky-customtkinter.svg)](https://hysenlabs.com/projects/tomschimansky-customtkinter)

Was this useful?