Textual Textarea
Note: This is NOT the official TextArea widget!
With v0.38.0, Textual added a built-in TextArea widget. You probably want to use that widget instead of this one. This project predated the official widget; versions < v0.8.0 had a completely separate implmentation.
Since v0.8.0, this project uses the built-in TextArea widget, but adds the features outlined below.
Installation
pip install textual-textarea
Features
Full-featured text editor experience with VS-Code-like bindings, in your Textual App:
- Syntax highlighting and support for Pygments themes.
- Move cursor and scroll with mouse or keys (including ctrl+arrow, PgUp/Dn, ctrl+Home/End).
- Open (ctrl+o) and save (ctrl+s) files.
- Cut (ctrl+x), copy (ctrl+c), paste (ctrl+u/v), optionally using the system clipboard. On terminals that support the Kitty keyboard protocol, the cmd equivalents work too.
- Delete a word with ctrl+backspace, alt+backspace, or alt+delete.
- Comment selections with ctrl+/.
- Indent and dedent (optionally for a multiline selection) to tab stops with Tab and shift+Tab.
- Automatic completions of quotes and brackets.
- Select text by double-, triple-, or quadruple-clicking.
- Quit with ctrl+q.
Usage
Initializing the Widget
The TextArea is a Textual Widget. You can add it to a Textual
app using compose or mount:
from textual_textarea import TextEditor
from textual.app import App, ComposeResult
class TextApp(App, inherit_bindings=False):
def compose(self) -> ComposeResult:
yield TextEditor(text="hi", language="python", theme="nord-darker", id="ta")
def on_mount(self) -> None:
editor = self.query_one("#id", expect_type=TextEditor)
editor.focus()
app = TextApp()
app.run()
In addition to the standard Widget arguments, TextArea accepts three additional, optional arguments when initializing the widget:
- language (str): Must be
Noneor the short name of a Pygments lexer, e.g.,python,sql,as3. Defaults toNone. - theme (str): Must be name of a Pygments style, e.g.,
bw,github-dark,solarized-light. Defaults tomonokai. - use_system_clipboard (bool): Set to
Falseto make the TextArea's copy and paste operations ignore the system clipboard. Defaults toTrue. Some Linux users may need to apt-installxcliporxselto enable the system clipboard features.
The TextArea supports many actions and key bindings. For proper binding of ctrl+c to the COPY action,
you must initialize your App with inherit_bindings=False (as shown above), so that ctrl+c does not quit the app. The TextArea implements ctrl+q as quit; you way wish to mimic that in your app so that other in-focus widgets use the same behavior.
Interacting with the Widget
Getting and Setting Text
The TextArea exposes a text property that contains the full text contained in the widget. You can retrieve or set the text by interacting with this property:
editor = self.query_one(TextEditor)
old_text = editor.text
editor.text = "New Text!\n\nMany Lines!"
Similarly, the TextEditor exposes a selected_text property (read-only):
editor = self.query_one(TextEditor)
selection = editor.selected_text
Inserting Text
You can insert text at the current selection:
editor = self.query_one(TextEditor)
editor.text = "01234"
editor.selection = Selection((0, 2), (0, 2))
editor.insert_text_at_selection("\nabc\n")
assert editor.text == "01\nabc\n234"
assert editor.selection == Selection((2, 0), (2, 0))
Getting and Setting The Cursor Position
The TextEditor exposes a selection property that returns a textual.widgets.text_area.Selection:
editor = self.query_one(TextEditor)
old_selection = editor.selection
editor.selection = Selection((999, 0),(999, 0)) # the cursor will move as close to line 999, pos 0 as possible
cursor_line_number = editor.selection.end[0]
cursor_x_position = editor.selection.end[1]
Getting and Setting The Language
Syntax highlighting and comment insertion depends on the configured language for the TextEditor.
The TextArea exposes a language property that returns None or a string that is equal to the short name of an installed tree-sitter language:
editor = self.query_one(TextEditor)
old_language = editor.language
editor.language = "python"
Getting Theme Colors
If you would like the rest of your app to match the colors from the TextArea's theme, they are exposed via the theme_colors property.
editor = self.query_one(TextEditor)
color = editor.theme_colors.contrast_text_color
bgcolor = editor.theme_colors.bgcolor
highlight = editor.theme_colors.selection_bgcolor
Adding Bindings and other Behavior
You can subclass TextEditor to add your own behavior. This snippet adds an action that posts a Submitted message containing the text of the TextEditor when the user presses ctrl+j:
from textual.message import Message
from textual_textarea import TextEditor
class CodeEditor(TextEditor):
BINDINGS = [
("ctrl+j", "submit", "Run Query"),
]
class Submitted(Message, bubble=True):
def __init__(self, text: str) -> None:
super().__init__()
self.text = text
async def action_submit(self) -> None:
self.post_message(self.Submitted(self.text))
Release files for textual-textarea 0.18.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| textual_textarea-0.18.3.tar.gz | 29.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| textual_textarea-0.18.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.5 kB
Release files / textual_textarea-0.18.3.tar.gz
| Download URL | textual_textarea-0.18.3.tar.gz |
|---|---|
| Size | 29.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
76dd59534390fcb126c5a84a7de630d5e7b8f2b3b4bc5912ec7fdee294668825
|
|
BLAKE2b-256 checksum How to use checksums |
fc95544a5bf903068e46dbe30e9faca3c0f373c5d964b4c226b4acd97657e9e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.
Transparency logRelease files / textual_textarea-0.18.3-py3-none-any.whl
| Download URL | textual_textarea-0.18.3-py3-none-any.whl |
|---|---|
| Size | 27.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
df9b086a7a685fe78593ec7fa67070411bbbf1f01f72bb849727ca5289e98c8e
|
|
BLAKE2b-256 checksum How to use checksums |
9220b70ae6b1433ef80805d860ed5741d40ab5f1ee34d93a51360937702c776d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 16, 2026.
Transparency log