2026, Jan 05 13:00
Stop the ghost highlight in Tkinter Listbox: align selection with the active item and fix arrow-key navigation
Learn why Tkinter Listbox shows a ghost highlight and how to sync selection with the active item. Fix focus issues, arrow-key navigation, activestyle.
When a Tkinter Listbox regains focus after you tab through other widgets, you may notice a second highlight that doesn’t match the selected row. Arrow keys then move from this ghosted highlight rather than from the row you explicitly selected. This is confusing because visually you have one selection, but navigation behaves as if there’s another.
Reproducing the mismatch
The typical sequence is to clear the selection and then select a specific row. That part works: the intended item is visibly selected. The divergence appears after focus leaves and comes back.
import tkinter as tk
root = tk.Tk()
items_box = tk.Listbox(root)
items_box.pack()
for label in ["001_adf", "007_adf", "010_adf"]:
items_box.insert(tk.END, label)
row_idx = 2 # for example, "010_adf"
items_box.selection_clear(0, tk.END)
items_box.selection_set(row_idx)The selection is correct, yet after navigating away and back, the keyboard cursor appears to attach to a different row, and Up/Down start from that misplaced highlight.
What’s actually happening
The extra highlight is the Listbox’s active item. It’s analogous to a text cursor: a focus-aware position that can differ from the selection. Up/Down move from the active item, not from the selection you set. Anchoring the selection doesn’t fix this because the active item is a separate concept.
Making selection and navigation agree
To align keyboard navigation with your chosen row, set the active item alongside the selection. You can also hide the active-item styling if you don’t want it visible.
# keep visible selection and keyboard start in sync
items_box.selection_clear(0, tk.END)
items_box.selection_set(row_idx)
items_box.activate(row_idx)If you prefer to remove the active-item highlight entirely, configure the Listbox with no active style. This keeps behavior unchanged while removing the visual “shadow.”
items_box = tk.Listbox(root, activestyle="none")If you want the selected row to remain visibly selected even when the Listbox loses focus, disable selection export.
items_box = tk.Listbox(root, exportselection=False)Why this matters
UI consistency is not cosmetic. When selection and navigation start points diverge, users press a key and land on an unexpected row. Explicitly managing the active item removes that disconnect and keeps keyboard interaction predictable, especially in forms where focus moves frequently.
Practical wrap‑up
Set the selection and the active item together whenever you programmatically choose a row. Hide the active style if you don’t want the secondary highlight, and use exportselection=False when you need the chosen row to stay visibly selected across focus changes. These small adjustments make Listbox behavior line up with user expectations and reduce navigation surprises.