If you need a yes/no option in a Python window, a Tkinter Checkbutton tied to a BooleanVar is the answer: the box toggles the variable, and var.get() tells you whether it’s checked.
agree = tk.BooleanVar()
tk.Checkbutton(root, text="I agree", variable=agree).pack()
Most people get stuck on reading the value, running code on a click, or a ttk box that starts half-checked.
In this tutorial, I’ll build a small checkout form step by step on Python 3.12.5 with Tk 8.6, with every window captured from a real run on Windows 11.
The sample Checkbutton data: checkout add-ons
Every example uses four add-ons from a bike shop checkout: a $49.99 helmet, $24.50 bike lights, a $35.00 U-lock and $5.00 gift wrap.
Method 1: Create a Tkinter Checkbutton with BooleanVar (Recommended)
Use this for a single on/off choice. Here’s the gift wrap option on its own, with a label that reports the state:
import tkinter as tk
root = tk.Tk()
root.title("Gift wrap")
root.geometry("400x150")
wrap = tk.BooleanVar(value=False)
def show_choice():
status.config(text=f"Gift wrap selected: {wrap.get()}")
check = tk.Checkbutton(root, text="Add gift wrap ($5.00)",
variable=wrap, command=show_choice)
check.pack(pady=(24, 8))
status = tk.Label(root, text="Gift wrap selected: False")
status.pack()
root.mainloop()

How does this code work?
variable=wrap links the box to the BooleanVar, so a click flips it between False and True. An IntVar would hold 0 and 1.
command=show_choice runs after each click, once the variable already holds the new value. The guide to getting a Tkinter Checkbutton value covers IntVar and reading the value later.
Method 2: Run code when a Checkbutton is clicked
Same checkout form, now with all four add-ons. Each box gets its own BooleanVar in a dictionary, and every box calls one function that recalculates the total:
import tkinter as tk
ADDONS = {"Helmet": 49.99, "Bike lights": 24.50,
"U-lock": 35.00, "Gift wrap": 5.00}
root = tk.Tk()
root.title("Checkout add-ons")
root.geometry("400x230")
choices = {}
def update_total():
total = sum(price for name, price in ADDONS.items()
if choices[name].get())
total_label.config(text=f"Add-ons total: ${total:.2f}")
for name, price in ADDONS.items():
choices[name] = tk.BooleanVar()
tk.Checkbutton(root, text=f"{name} (${price:.2f})",
variable=choices[name],
command=update_total).pack(anchor="w", padx=20)
total_label = tk.Label(root, text="Add-ons total: $0.00")
total_label.pack(pady=12)
root.mainloop()

How does this code work?
The loop builds one Checkbutton per dictionary entry. update_total() sums only the prices whose variable is True: $49.99 + $35.00 = $84.99.
Important: pass the function itself, command=update_total, not update_total(). The same rule is explained in the Tkinter button command tutorial.
Method 3: Store custom values with onvalue and offvalue
Sometimes you want text instead of True/False, like a shipping code you’ll send to an API. Point the box at a StringVar and set onvalue and offvalue:
import tkinter as tk
root = tk.Tk()
shipping = tk.StringVar(value="standard")
fast = tk.Checkbutton(root, text="Express shipping",
variable=shipping,
onvalue="express", offvalue="standard")
fast.pack()
print("Start:", shipping.get())
fast.invoke() # same as a click
print("After a click:", shipping.get())
root.destroy()
Output:
Start: standard
After a click: express
The variable moved from standard to express after invoke(), which acts like a real click and also runs the command. select() and deselect() only change the state.
If only one choice in a group may be on, use a Tkinter Radiobutton instead.
How do I make a Tkinter Checkbutton checked by default?
Start the variable at tk.BooleanVar(value=True), or call check.select() after creating the box. More options are in the post on a Tkinter checkbox checked by default.
Method 4: Add a Select all Checkbutton in a grid
Same checkout form again, now in a two-column grid with a Select all box. It sets every variable, and each item box updates the Select all state:
import tkinter as tk
ADDONS = {"Helmet": 49.99, "Bike lights": 24.50,
"U-lock": 35.00, "Gift wrap": 5.00}
root = tk.Tk()
root.title("Select all add-ons")
root.geometry("400x180")
choices = {name: tk.BooleanVar() for name in ADDONS}
all_var = tk.BooleanVar()
def refresh():
picked = [n for n, v in choices.items() if v.get()]
all_var.set(len(picked) == len(ADDONS))
total = sum(ADDONS[n] for n in picked)
summary.config(text=f"{len(picked)} selected, ${total:.2f}")
def toggle_all():
for var in choices.values():
var.set(all_var.get())
refresh()
select_all = tk.Checkbutton(root, text="Select all",
variable=all_var, command=toggle_all)
select_all.grid(row=0, column=0, sticky="w", padx=16, pady=(12, 4))
for i, name in enumerate(ADDONS):
tk.Checkbutton(root, text=name, variable=choices[name],
command=refresh).grid(row=1 + i // 2, column=i % 2,
sticky="w", padx=(32, 8))
summary = tk.Label(root, text="0 selected, $0.00")
summary.grid(row=3, column=0, columnspan=2, sticky="w", padx=16, pady=12)
root.mainloop()

How does this code work?
toggle_all() copies the Select all value into every add-on variable. refresh() keeps Select all checked only while all four are picked.
Placing the boxes with row and column is covered in the Tkinter grid layout guide.
Style or disable a Checkbutton with ttk
ttk.Checkbutton follows the Windows theme, so it looks native. Here’s a delivery panel with a checked, a disabled and a variable-less box:
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
root.title("Delivery options")
root.geometry("400x150")
express = tk.BooleanVar(value=True)
ttk.Checkbutton(root, text="Express shipping ($12.00)",
variable=express).pack(anchor="w", padx=20, pady=(16, 4))
gift = tk.BooleanVar()
wrap = ttk.Checkbutton(root, text="Gift wrap (sold out)", variable=gift)
wrap.state(["disabled"])
wrap.pack(anchor="w", padx=20, pady=4)
no_var = ttk.Checkbutton(root, text="Leave at the door")
no_var.pack(anchor="w", padx=20, pady=4)
root.mainloop()

wrap.state(["disabled"]) grays the box out; on classic widgets use state="disabled". For fonts and colors on text near the boxes, see the Tkinter Label tutorial.
So here’s the catch: “Leave at the door” has no variable, so it starts in the alternate state (the dash).
Which Checkbutton method should you use?
| Need | Use |
|---|---|
| One yes/no option | BooleanVar + variable= |
| React to every click | command=func |
| Text values | onvalue / offvalue |
| Many options | Dict of variables + Select all |
| Native look or disabled | ttk.Checkbutton |
Things to keep in mind with Tkinter Checkbuttons
- Keep a reference to every variable; in my run, an inline
tk.BooleanVar()was garbage-collected and showed the dash. commandisn’t called byvar.set()orselect(), only by clicks andinvoke().- Give every ttk Checkbutton a variable to avoid the alternate dash.
Keep building the form with these next:
- Python Tkinter Button
- Set the Tkinter window size
- Add images in Tkinter
- Python GUI programming with Tkinter
Frequently asked questions
How do I create a checkbox in Python Tkinter?
Use tk.Checkbutton(root, text="...", variable=var) with a BooleanVar, then pack() it.
How do I get the value of a Tkinter Checkbutton?
Call get() on its variable.
How do I run a function when a Checkbutton is clicked?
Pass command=func without parentheses.
How do I uncheck a Checkbutton from code?
Use var.set(False) or check.deselect(). Neither one calls the command.
Why does my ttk Checkbutton show a dash?
It has no variable. Pass variable=tk.BooleanVar().
Where is ttk.Checkbutton documented?
See ttk Checkbutton in the Python docs.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn