The Tkinter Listbox widget displays a vertical list of single-line items. Depending on its selectmode, the user can select one item or several items.

import tkinter as tk
root=tk.Tk()
root.geometry('400x250')
root.title('Tkinter Listbox - plus2net')
font1=('Arial', 15)
lb1=tk.Listbox(root, height=6, font=font1, bg='lightgreen')
lb1.grid(row=0, column=0, padx=30, pady=20)
lb1.insert(tk.END, 'PHP')
lb1.insert(tk.END, 'MySQL')
lb1.insert(tk.END, 'Python')
lb1.insert(tk.END, 'JavaScript')
root.mainloop()
Each item appears on a separate line. The Listbox itself does not provide a drop-down button; the choices remain visible inside the widget.
The syntax is:
listbox.insert(index, item1, item2, ...)
lb1.insert(tk.END, 'Python')
lb1.insert(0, 'HTML')
lb1.insert(tk.END, 'PHP', 'Python', 'MySQL')
languages=['PHP', 'Python', 'MySQL']
for language in languages:
lb1.insert(tk.END, language)
The first Listbox item has index 0.
lb1.insert(tk.END, 'PHP')
lb1.insert(tk.END, 'Python')
lb1.insert(tk.END, 'MySQL')
print(lb1.get(0))
print(lb1.get(2))
Sample Output
PHP
MySQL
For insert(), tk.END represents the position after the final item, so it is the clearest way to append new data.
value=lb1.get(1)
print(value)
values=lb1.get(0, tk.END)
print(values)
Sample Output
('PHP', 'Python', 'MySQL')
When a range is requested, get() returns the items as a tuple.
curselection() returns a tuple containing the indexes of all currently selected items.
selected=lb1.curselection()
print(selected)
With one selected item:
(1,)
If nothing is selected:
()
selected=lb1.curselection()
if selected:
index=selected[0]
value=lb1.get(index)
print(index, value)
selected[0] when no item is selected raises an IndexError.import tkinter as tk
def show_selected():
selected=lb1.curselection()
if selected:
print(lb1.get(selected[0]))
else:
print('No item selected')
root=tk.Tk()
lb1=tk.Listbox(root, height=4)
lb1.pack(padx=20, pady=10)
for item in ('PHP', 'Python', 'MySQL'):
lb1.insert(tk.END, item)
tk.Button(root, text='Show Selected', command=show_selected).pack(pady=10)
root.mainloop()
The virtual event <<ListboxSelect>> is generated when the Listbox selection changes.
import tkinter as tk
def selection_changed(event):
selected=event.widget.curselection()
if not selected:
return
index=selected[0]
value=event.widget.get(index)
print('Selected:', index, value)
root=tk.Tk()
lb1=tk.Listbox(root)
lb1.pack(padx=20, pady=20)
for item in ('PHP', 'Python', 'MySQL'):
lb1.insert(tk.END, item)
lb1.bind('<<ListboxSelect>>', selection_changed)
root.mainloop()
Using event.widget makes the callback reusable with different Listbox widgets.
These concepts are related but are not interchangeable.
| Value / Method | Meaning |
|---|---|
curselection() | Indexes of items currently selected by the user or application. |
tk.ACTIVE | The active/location-cursor item. |
tk.ANCHOR | The selection anchor used when extending a selection. |
print(lb1.get(tk.ACTIVE))
This reads the active item, but it should not be used as a replacement for curselection() when the application needs the user's selected value.
lb1.activate(2)
curselection() to find selected items. Treat ACTIVE and ANCHOR as Listbox navigation/selection-state concepts.
A StringVar can be connected to a Label and updated whenever the Listbox selection changes.
import tkinter as tk
def selection_changed(event):
selected=lb1.curselection()
if selected:
output_var.set(lb1.get(selected[0]))
else:
output_var.set('')
root=tk.Tk()
root.geometry('450x250')
lb1=tk.Listbox(root, height=6, font=('Arial', 15), bg='lightgreen')
lb1.grid(row=0, column=0, padx=30, pady=20)
for item in ('PHP', 'Python', 'MySQL', 'HTML', 'jQuery'):
lb1.insert(tk.END, item)
output_var=tk.StringVar()
label=tk.Label(root, textvariable=output_var, bg='lightyellow', font=('Arial', 15))
label.grid(row=0, column=1, padx=5)
lb1.bind('<<ListboxSelect>>', selection_changed)
root.mainloop()

Set selectmode to multiple or extended when several items may be selected.
lb1=tk.Listbox(root, selectmode=tk.MULTIPLE)
curselection() can then contain several indexes.
def show_selected(event=None):
selected=lb1.curselection()
values=[lb1.get(index) for index in selected]
output_var.set(', '.join(values))
import tkinter as tk
def selection_changed(event):
selected=lb1.curselection()
values=[lb1.get(index) for index in selected]
output_var.set(', '.join(values))
root=tk.Tk()
lb1=tk.Listbox(root, height=6, selectmode=tk.MULTIPLE, exportselection=False)
lb1.grid(row=0, column=0, padx=10, pady=20)
for item in ('PHP', 'Python', 'MySQL', 'HTML', 'jQuery'):
lb1.insert(tk.END, item)
output_var=tk.StringVar()
tk.Label(root, textvariable=output_var, bg='lightyellow', width=30).grid(row=0, column=1, padx=10)
lb1.bind('<<ListboxSelect>>', selection_changed)
root.mainloop()
The list comprehension:
values=[lb1.get(index) for index in selected]
creates a Python list containing all selected values.
| Mode | Selection Behaviour |
|---|---|
tk.SINGLE | At most one item is selected. |
tk.BROWSE | At most one item is selected; this is the normal default browsing behaviour. |
tk.MULTIPLE | Several items can be toggled independently. |
tk.EXTENDED | Supports multiple selection including ranges using normal desktop selection behaviour. |
lb1=tk.Listbox(root, selectmode=tk.SINGLE)
lb1=tk.Listbox(root, selectmode=tk.BROWSE)
lb1=tk.Listbox(root, selectmode=tk.MULTIPLE)
lb1=tk.Listbox(root, selectmode=tk.EXTENDED)
MULTIPLE is useful when each item should be toggled independently. EXTENDED behaves more like a desktop file-selection list, where ranges and modifier-key selections are useful.lb1.selection_set(1)
lb1.selection_set(1, 3)
lb1.selection_clear(1)
lb1.selection_clear(0, tk.END)
print(lb1.selection_includes(2))
lb1.see(10)
lb1.delete(2)
This deletes the item at index 2, which is the third item.
lb1.delete(0, tk.END)
def delete_selected():
selected=lb1.curselection()
if selected:
lb1.delete(selected[0])
This is safer than assuming that tk.ANCHOR represents the selected item.
Delete indexes from highest to lowest so earlier deletions do not shift the remaining indexes.
def delete_selected():
selected=lb1.curselection()
for index in reversed(selected):
lb1.delete(index)
The simplest way to read all current Listbox values is:
items=lb1.get(0, tk.END)
print(items)
Sample Output
('PHP', 'Python', 'MySQL')
Use size():
print(lb1.size())
Sample Output
3
if lb1.size() > 0:
print(lb1.get(tk.END))
The listvariable option connects the Listbox contents to a Tkinter variable containing a Tcl list.
import tkinter as tk
root=tk.Tk()
items=('PHP', 'Python', 'MySQL')
items_var=tk.Variable(value=items)
lb1=tk.Listbox(root, listvariable=items_var)
lb1.pack(padx=20, pady=20)
print(items_var.get())
root.mainloop()
Sample Output
('PHP', 'Python', 'MySQL')
For simply reading the current Listbox contents, this is often clearer:
items=lb1.get(0, tk.END)
A Listbox inherits scrolling behaviour, so it can be connected to a vertical Scrollbar.
import tkinter as tk
from tkinter import ttk
root=tk.Tk()
frame=tk.Frame(root)
frame.pack(padx=20, pady=20)
scrollbar=ttk.Scrollbar(frame, orient='vertical')
scrollbar.pack(side='right', fill='y')
lb1=tk.Listbox(frame, height=8, yscrollcommand=scrollbar.set)
lb1.pack(side='left')
scrollbar.config(command=lb1.yview)
for number in range(1, 31):
lb1.insert(tk.END, f'Item {number}')
root.mainloop()
Tkinter Scrollbar Examples
| Option | Purpose |
|---|---|
bg / background | Background color. |
fg / foreground | Text color. |
font | Font family, size and style. |
height | Requested number of visible rows. |
width | Requested width in characters. |
selectmode | Controls single or multiple selection behaviour. |
selectbackground | Background color of selected items. |
selectforeground | Text color of selected items. |
state | normal or disabled. |
listvariable | Variable containing the Listbox items. |
exportselection | Controls whether the widget exports its selection to the window-system selection. |
activestyle | Appearance of the active item. |
cursor | Mouse cursor shown over the widget. |
relief | Border appearance. |
bd / borderwidth | Border width. |
highlightcolor | Focus-highlight color. |
highlightbackground | Highlight color when the widget does not have focus. |
highlightthickness | Width of the focus-highlight border. |
xscrollcommand | Connects a horizontal scrollbar. |
yscrollcommand | Connects a vertical scrollbar. |
lb1=tk.Listbox(root, bg='yellow', fg='green')
my_font=('Times', 12, 'underline')
lb1=tk.Listbox(root, font=my_font)
lb1=tk.Listbox(root, selectbackground='yellow', selectforeground='green')
lb1.config(state='disabled')
Enable it again:
lb1.config(state='normal')

lb1=tk.Listbox(root, highlightcolor='yellow', highlightthickness=5)

Common relief values are:
'raised'
'sunken'
'flat'
'ridge'
'solid'
'groove'
Example:
lb1=tk.Listbox(root, height=3, relief='ridge')
This option is especially useful when an interface contains more than one Listbox and each widget should retain its visible selection independently.
lb1=tk.Listbox(root, exportselection=False)
These widgets all present choices, but they suit different interfaces.
| Widget | Best Use | Multiple Selection |
|---|---|---|
| Listbox | Several choices should remain visible at the same time. | Yes |
| ttk.Combobox | Compact drop-down selection, optionally with editable text. | No |
| OptionMenu | Simple single-selection drop-down from a predefined set. | No |
The application needs a compact field with a drop-down list, especially when the available screen space is limited.
Tkinter Combobox TutorialListbox choices do not have to be hard-coded. They can also come from a database or another external data source.
Populate Listbox from Database TableA Listbox can display suggestions while the user types into an Entry field.
Tkinter Autocomplete using Entry and Listbox
Listbox displays single-line choices in a visible list.0.insert(tk.END, value) to append items.insert(index, ...) inserts items before the specified index.get(index) to read one item.get(0, tk.END) to read all items.size() to get the number of items.curselection() returns a tuple of selected indexes.curselection() is empty before accessing an index.<<ListboxSelect>> to react to selection changes.tk.ACTIVE represents the active item, not necessarily the selected item.tk.ANCHOR represents the selection anchor.selection_set() to select items programmatically.selection_clear() to deselect items.selectmode supports single, browse, multiple and extended.multiple or extended when several items may be selected.listvariable can provide Listbox contents through a Tkinter variable.exportselection=False when selections should remain independent across multiple selection widgets.Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.