Fix font rendering in browsers using WebGL/Canvas

Override xterm.js fontFamily via JavaScript since CSS cannot affect
canvas-rendered text. The terminal now uses the full monospace font
stack instead of falling back to Courier New.

Bumps version to 0.3.15
This commit is contained in:
GitHub Copilot
2026-01-25 12:15:16 +00:00
parent 5512c84ae1
commit 9f8770b168
2 changed files with 25 additions and 9 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "textual-webterm" name = "textual-webterm"
version = "0.3.14" version = "0.3.15"
description = "Serve terminal sessions over the web" description = "Serve terminal sessions over the web"
authors = ["Will McGugan <will@textualize.io>"] authors = ["Will McGugan <will@textualize.io>"]
license = "MIT" license = "MIT"
+24 -8
View File
@@ -855,16 +855,26 @@ class LocalServer:
<body> <body>
<div id=\"terminal\" class=\"textual-terminal\" data-session-websocket-url=\"{ws_url}\" data-font-size=\"16\"></div> <div id=\"terminal\" class=\"textual-terminal\" data-session-websocket-url=\"{ws_url}\" data-font-size=\"16\"></div>
<script> <script>
// Try to focus the terminal after it initializes // Override xterm.js font family (canvas/WebGL rendering ignores CSS)
(function() {{ (function() {{
const FONT_FAMILY = 'ui-monospace, "SFMono-Regular", "FiraCode Nerd Font", "FiraMono Nerd Font", "Fira Code", "Roboto Mono", Menlo, Monaco, Consolas, "Liberation Mono", "DejaVu Sans Mono", "Courier New", monospace';
function patchTerminal() {{
// textual.js stores terminal instance on the container element
const container = document.querySelector('.textual-terminal');
if (container && container.terminal) {{
container.terminal.options.fontFamily = FONT_FAMILY;
return true;
}}
return false;
}}
function focusTerminal() {{ function focusTerminal() {{
// xterm.js creates a textarea for input
const textarea = document.querySelector('.xterm-helper-textarea'); const textarea = document.querySelector('.xterm-helper-textarea');
if (textarea) {{ if (textarea) {{
textarea.focus(); textarea.focus();
return true; return true;
}} }}
// Also try focusing the terminal container
const term = document.querySelector('.xterm'); const term = document.querySelector('.xterm');
if (term) {{ if (term) {{
term.focus(); term.focus();
@@ -872,12 +882,18 @@ class LocalServer:
}} }}
return false; return false;
}} }}
// Try immediately and with delays as terminal initializes async
if (!focusTerminal()) {{ function initTerminal() {{
setTimeout(focusTerminal, 100); patchTerminal();
setTimeout(focusTerminal, 500); focusTerminal();
setTimeout(focusTerminal, 1000);
}} }}
// Try immediately and with delays as terminal initializes async
initTerminal();
setTimeout(initTerminal, 100);
setTimeout(initTerminal, 500);
setTimeout(initTerminal, 1000);
// Also focus on window focus (when switching tabs back) // Also focus on window focus (when switching tabs back)
window.addEventListener('focus', focusTerminal); window.addEventListener('focus', focusTerminal);
}})(); }})();