Library support¶
Note
This page is generated from src/textual_wasm/ecosystem.py by textual-wasm libraries,
and a test fails when the committed copy drifts from it. Every verdict came from installing
the distribution into a real Pyodide and mounting its widgets in a running Textual app.
Library support
37 Textual add-on libraries, probed inside Pyodide 314.0.6 against Textual 8.2.8 on 2026-09-12. 23 of them can be shipped to a browser today.
Measured in four tiers, because no single one of them is a verdict: micropip install, import, this project’s own static scan, and then the tier that decides a port - constructing every Widget subclass the library defines and mounting it in a running Textual app under the capture driver.
Two results before the table. On the first run of this survey the static scan produced no findings at all, across every library - which was a gap in the rules, not a clean bill of health. The two failures the runtime tier had already found showed where, and both now have registry entries that fire on the exact lines responsible. And the most-downloaded package here, textual-serve, installs and imports cleanly while being the one thing on this page you definitely should not use with it.
Warning
textual[syntax] does not install under Pyodide 314.0.6. Textual’s syntax extra needs tree-sitter>=0.25.0; Pyodide bundles 0.23.2 as a native wheel, which cannot be fetched from PyPI at another version. Found by way of textual-textarea, but not specific to it. micropip’s message - “can’t find a pure Python wheel for tree-sitter” - is misleading: it exists, one minor version too old.
A plain TextArea was never affected. For highlighting the whole gap is one class, so textual_wasm.treesitter supplies it and TextArea.code_editor(language=...) works for the three grammars Pyodide bundles - python, go and java. Measured in Chromium and Firefox: 14 and 13 distinct colours painted, typing still reparsing, no console errors. The other twelve languages in the extra have no Pyodide recipe at all.
Ordered by monthly PyPI downloads within each group, so the rows people are most likely to want come first. Run textual-wasm doctor <module:App> -r <dist> to check your own dependencies the same way.
Works
Installed, imported, and at least one of the library’s own widgets mounted and rendered inside a running Textual application under Pyodide. This is the only row class that means works in a browser - the three tiers below it are each a weaker claim, and they fail for unrelated reasons.
Distribution |
Downloads/month |
What it is |
What the probe saw |
|---|---|---|---|
|
675,128 |
dropdown autocompletion for Input |
|
|
254,448 |
images via Sixel and the Terminal Graphics Protocol |
|
|
207,180 |
Plotext charts as a Textual widget |
All 6 widgets constructed, mounted and rendered. No native dependency. Mounted: |
108,980 |
DirectoryTree over local and remote filesystems |
|
|
|
57,158 |
a DataTable backed by Arrow, for large tables |
Installed and its widget mounted and rendered. Mounted: |
|
50,738 |
file open/save and directory picker dialogs |
10 of 11 widgets mounted and rendered, including |
|
31,124 |
a high-resolution drawing canvas |
Installed and its widget mounted and rendered. Mounted: |
|
31,046 |
a native plotting widget with zoom and pan |
All 7 widgets constructed, mounted and rendered. Mounted: |
|
14,601 |
an image viewer widget |
|
|
10,488 |
a date picker |
6 of 9 widgets mounted and rendered; the other 3 need constructor arguments. Mounted: |
|
4,600 |
an assorted widget collection |
20 of 28 widgets mounted and rendered; 6 need constructor arguments and 2 are abstract bases that cannot be constructed anywhere. |
|
3,197 |
a slider |
|
|
2,396 |
a colour picker |
All 8 widgets mounted and rendered. Mounted: |
|
1,166 |
date, time, duration and timeline widgets |
42 of 50 widgets mounted and rendered. Its Textual requirement is |
|
421 |
a character-cell drawing canvas |
|
|
70 |
a tag-entry widget |
|
|
48 |
a visual countdown timer |
Its widget mounted and rendered. Mounted: |
|
25 |
a Python AST explorer |
|
|
8 |
a dad joke widget, seriously |
Its widget mounted and rendered. Mounted: |
Installs, not exercised
Installs and imports cleanly, but nothing could be mounted automatically: either it defines no Textual widget at all (a Rich renderable, a stylesheet) or every widget it defines needs constructor arguments a generic probe cannot invent. Absence of evidence, listed as such and not rounded up to working.
Distribution |
Downloads/month |
What it is |
What the probe saw |
|---|---|---|---|
|
93,903 |
images as Rich renderables |
Installs and imports. Defines no Textual widget - it is a Rich renderable, so it reaches a Textual app through |
|
8 |
Tailwind-like utility classes for Textual CSS |
Installs and imports. Ships stylesheets, not widgets, so nothing to mount. |
|
7 |
a PDF preview widget, on top of textual-image |
Installs and imports; |
|
- |
a select/dropdown with a searchable list |
Installs and imports. All four of its widgets need constructor arguments ( |
Caps Textual below this build’s
Requires a Textual older than the 8.2.8 this project pins. The trap is that micropip.install(name) on its own succeeds - it quietly resolves Textual down to a version the cap allows, and you discover the downgrade later as missing widgets or changed APIs. None of this is a WASM constraint: the same cap binds a terminal install identically.
Distribution |
Downloads/month |
What it is |
What the probe saw |
|---|---|---|---|
|
1,587 |
a sliding or hidden menu-bar container |
Requires |
|
1,475 |
animated colour effects and tiled backgrounds |
Requires |
|
1,384 |
Pyfiglet banner text with colour and animation |
Requires |
|
78 |
floating, draggable windows and a window manager |
Requires |
|
13 |
a spinbox |
Requires |
Cannot be installed
The install fails under Pyodide. Read the middle column before assuming the reason is WebAssembly - three of these are ordinary dependency pins that would fail anywhere, and only the first is about a missing native build.
Distribution |
Downloads/month |
What it is |
What the probe saw |
|---|---|---|---|
48,465 |
a full text editor widget, from the Harlequin project |
Depends on |
|
|
2,695 |
embed another terminal application inside Textual |
Installs, then fails to import: |
72 |
a drag-and-drop FileDrop widget |
Requires |
|
27 |
display Pandas dataframes in Textual |
Pins |
|
|
11 |
a QR code widget |
Pins |
Not packaged
No distribution exists to install. micropip fetches from PyPI or a URL and has no path to a git repository, so the fix is to vendor the source into your own package - where the build ships it like any other module.
Distribution |
Downloads/month |
What it is |
What the probe saw |
|---|---|---|---|
- |
transition effects for widgets |
|
Not something you ship to a page
Installs fine and is still the wrong tool here: a development dependency, or the server-side architecture this project is the alternative to. Listed because between them they are the most-downloaded packages in the survey, so “it installed” would otherwise read as an endorsement.
Distribution |
Downloads/month |
What it is |
What the probe saw |
|---|---|---|---|
|
1,128,421 |
serve a Textual app over HTTP from a Python server |
Installs and imports under Pyodide, which is precisely why the install tier alone is not a verdict. The doctor now flags |
|
397,962 |
Textual’s development tools and console |
Installs and imports under Pyodide. A development dependency: run it on your machine against the terminal build. Its console talks to a devtools server over a socket, which a page cannot open. |
|
281,667 |
snapshot testing for Textual apps |
Installs and imports under Pyodide. Test on the terminal build, where it runs under pytest normally. For checking that the browser renders identically, |
What this does not tell you
WebKit is unmeasured. It would not launch on the machine that ran these probes, so every verdict is Chromium and Firefox. See browser support.
Mounting is not using. A widget that mounts and renders can still fail on an interaction nobody drove. Libraries that reach the network (
textual-qrcode,textual-dad-joke) or a real filesystem (textual-fspicker,textual-universal-directorytree) were mounted, not exercised end to end - and in a browser those two are exactly where CORS and MEMFS bite.Versions move. Every row is one version on one date. A
textual_capverdict in particular is the most likely to be fixed by the library’s next release.