The Python Tkinter Text widget is what you reach for the moment a single input box stops being enough. It handles multi-line input, per-character styling, bookmarks, and even embedded images, which makes it the backbone of text editors, chat windows, log viewers, and note-taking tools built in Tkinter.
Table of Contents
This guide covers the syntax, the configuration options worth knowing, the methods you will actually use, and a working example with tag-based formatting. By the end you will be able to build a formatted text area and manipulate its contents programmatically.
Why Use the Tkinter Text Widget
Tkinter ships with the Entry widget for simple input, but Entry is limited to a single line of unformatted text. The Text widget removes that ceiling. It accepts as many lines as you need, applies different fonts and colours to different regions of the same content, and lets you insert images or other widgets inline.
That difference matters as soon as your application needs to display a document, accept a message body, or show output that grows over time. Anywhere a user types more than a name or a number, the Text widget is the correct choice.
| Capability | Entry Widget | Text Widget |
|---|---|---|
| Multi-line input | No | Yes |
| Mixed formatting | No | Yes, using tags |
| Embedded images | No | Yes |
| Scrollbar support | Horizontal only | Both directions |
| Typical use | Name, email, search box | Editor, chat, log output |
Syntax of the Text Widget
w = Text(top, options)
Here top is the parent window or frame the widget belongs to, and options are keyword arguments that control appearance and behaviour. The widget still needs a geometry manager call such as pack(), grid(), or place() before it appears on screen.
Key Options for the Text Widget
| Option | Description |
|---|---|
bg | Background colour of the text area. |
fg | Colour of the text itself. |
bd | Border width in pixels. |
cursor | Mouse pointer shape shown over the widget. |
font | Font family, size, and style. |
height | Visible height measured in lines, not pixels. |
width | Visible width measured in characters. |
padx | Horizontal padding inside the widget. |
pady | Vertical padding inside the widget. |
wrap | Wrapping mode: WORD, CHAR, or NONE. |
state | Set to DISABLED to make the content read-only. |
xscrollcommand | Connects a horizontal scrollbar. |
yscrollcommand | Connects a vertical scrollbar. |
One point that catches beginners out: height and width are counted in text units, not pixels. A width of 30 means thirty characters of the current font, so changing the font changes the physical size of the widget.
Understanding Text Indexes
Every method that touches content needs a position, and Tkinter expresses positions as strings. Lines are counted from 1 and columns from 0, which is an inconsistency worth memorising early.
- “1.0” is the very first character of the widget.
- “2.5” is the sixth character on the second line.
- END is the position just past the last character.
- INSERT is the current position of the blinking cursor.
- “1.0 lineend” and similar modifiers let you move relative to a known point.
Ranges are always half-open. A range from "1.0" to "1.5" Covers five characters at columns 0 through 4, and stops before column 5.
Useful Methods of the Text Widget
Basic Text Operations
| Method | Description |
|---|---|
insert(index, text) | Inserts text at the given position. |
get(start, end) | Returns the text within a range. |
delete(start, end) | Removes the text within a range. |
index(index) | Resolves any index expression to a concrete line.column value. |
see(index) | Scrolls the widget so the given position becomes visible. |
Mark Handling Methods
Marks are named bookmarks that float between characters. They move automatically as text is inserted or deleted around them, which makes them useful for tracking a position you will need later.
| Method | Description |
|---|---|
mark_set(mark, index) | Places a named mark at a position. |
mark_unset(mark) | Removes a mark. |
mark_gravity(mark, gravity) | Controls whether the mark stays left or right of text inserted at its position. |
Tag Handling Methods
Tags are named ranges you can style independently. Attach a tag to a region, configure its appearance once, and every region carrying that tag updates together.
| Method | Description |
|---|---|
tag_add(name, start, end) | Applies a tag to a range of text. |
tag_config(name, options) | Sets colours, fonts, and other styling for the tag. |
tag_remove(name, start, end) | Strips a tag from a range without deleting the tag. |
tag_delete(name) | Removes the tag entirely along with its configuration. |
tag_bind(name, event, handler) | Binds an event, such as a click, to tagged text. |
Example: Formatting Text With Tags
This example creates a Text widget, inserts two lines, and applies two different tags to highlight parts of the first line.
from tkinter import *
top = Tk()
top.title("Tkinter Text Widget Example")
text = Text(top, height=5, width=30)
text.insert(INSERT, "Enter your Name...")
text.insert(END, "\nEnter your Salary...")
text.pack()
text.tag_add("highlight", "1.0", "1.5")
text.tag_add("alert", "1.11", "1.15")
text.tag_config("highlight", background="yellow", foreground="black")
text.tag_config("alert", background="black", foreground="white")
top.mainloop()
What the Example Does
- Line 1 insertion:
INSERTplaces the first string at the cursor, which starts at position 1.0. - Line 2 insertion: the
\nescape starts a new line before the second string. Writing a barenhere is a common typo that produces one long line instead. - The highlight tag: covers columns 0 to 4 of line one, which is the word “Enter”, shown on a yellow background.
- The alert tag: covers columns 11 to 14, which is the word “Name”, shown as white text on black.
Count the characters yourself to confirm the column numbers. Getting index arithmetic wrong is the single most frequent bug when working with the Python Tkinter Text widget, and printing text.get("1.0", "1.5") is the fastest way to verify a range before styling it.
Adding a Scrollbar
A Text widget does not scroll by itself. You create a Scrollbar, point the widget at it, and point it back at the widget.
from tkinter import *
top = Tk()
scrollbar = Scrollbar(top)
scrollbar.pack(side=RIGHT, fill=Y)
text = Text(top, height=10, width=40, wrap=WORD,
yscrollcommand=scrollbar.set)
text.pack(side=LEFT, fill=BOTH, expand=True)
scrollbar.config(command=text.yview)
for i in range(1, 31):
text.insert(END, "Line number " + str(i) + "\n")
top.mainloop()
The two-way link matters. yscrollcommand tells the scrollbar where the view currently is, and command=text.yview tells the widget to move when the scrollbar is dragged. Omit either one and the scrollbar will look correct but behave oddly.
Common Mistakes to Avoid
- Counting lines from zero: the first line is 1, not 0. Columns, confusingly, do start at 0.
- Forgetting the trailing newline: Tkinter appends a newline at the end of the content, so
get("1.0", END)returns one extra character. Useget("1.0", "end-1c")to trim it. - Inserting into a disabled widget: if
stateisDISABLED, switch it toNORMAL, insert, then disable it again. - Styling before inserting: a tag applied to a range that does not exist yet silently does nothing.
- Using pixel thinking:
widthandheightare character and line counts, so they shift with the font.
Conclusion
The Python Tkinter Text widget turns a basic window into something capable of holding real content. Once you are comfortable with the line.column index format, the insert and delete methods, and tag-based styling, you have everything needed to build a working editor, a chat panel, or a formatted output console.
The most productive next step is to combine what is covered here into one small application: a text area with a scrollbar, a save button that writes the content to a file, and a tag that highlights search matches. That single exercise exercises almost every method in this guide.
Watch the Tutorial
Step-by-step Python GUI walkthroughs, including Tkinter widget builds explained line by line, are published on the channel’
.Subscribe to DecodeIT2 on YouTube
Frequently Asked Questions
What is the difference between the Text and Entry widgets?
Entry accepts a single line of plain text and is meant for short values such as a name or a search term. The Text widget accepts unlimited lines, supports mixed formatting through tags, and can embed images and other widgets.
How do I get all the text from a Tkinter Text widget?
Call text.get("1.0", "end-1c"). Using END alone works but includes the automatic trailing newline that Tkinter maintains internally.
Can I make the Text widget read-only?
Yes. Pass state=DISABLED when creating it, or set it later with text.config(state=DISABLED). Remember to switch back to NORMAL before inserting programmatically.
Does the Text widget support rich text like bold and italic?
It supports per-range styling through tags, so you can apply a bold font to one region and an italic font to another. It is not a full rich text editor, but tags cover fonts, colours, spacing, and justification.
Is Tkinter still worth learning in 2026?
For desktop tools, academic projects, and quick internal utilities, yes. It ships with Python, needs no installation, and remains one of the fastest ways to put a working interface around a script.