2025, Sep 24 19:00

PySide6 QTableView edit mode on dark backgrounds: make the editor text readable with a custom delegate

Learn why QTableView edit mode ignores model colors in PySide6 and how a QStyledItemDelegate with a proper palette fixes unreadable text on dark themes. See how.

Editing text inside a QTableView on a dark-styled window can look perfect in display mode and then suddenly become unreadable when the user starts typing. If your PySide6 app sets a dark background for the parent QDialog and paints table cells in white via the model, the editor that appears in edit mode might still show black text under a light OS theme, making the content barely visible. Here’s why that happens and how to fix it cleanly.

Problem setup

The window uses a dark background with a stylesheet, the table header is transparent, the model paints cell text white, and items are editable. In code it looks like this:

from PySide6 import QtCore, QtGui, QtWidgets
dlg = QtWidgets.QDialog()
dlg.setStyleSheet("background-color: #11375E;")
view = QtWidgets.QTableView(dlg)
view.setStyleSheet(
    "QHeaderView::section {\n"
    "background-color: transparent;\n"
    "border-style: hidden\n"
    "}"
)
class GridModel(QtCore.QAbstractTableModel):
    def data(self, ix, role):
        match role:
            case QtCore.Qt.ItemDataRole.ForegroundRole:
                return QtGui.QBrush(QtGui.QColorConstants.White)
        return super().data(ix, role)
    def flags(self, ix):
        return (
            QtCore.Qt.ItemFlag.ItemIsEnabled |
            QtCore.Qt.ItemFlag.ItemIsEditable
        )

In display mode this looks correct on both dark and light OS themes. The issue appears only in edit mode: under a light theme the typed text is black over a dark background and is hard to read.

What’s really happening in edit mode

When a cell enters edit mode, the view doesn’t recolor the painted cell. Instead, it creates a standalone editor widget—by default a frameless QLineEdit for string values—positioned over that cell. That editor is a normal widget and it inherits its palette from the parent. The ForegroundRole you return from the model doesn’t influence the editor’s appearance. Similarly, QSS rules applied to the view or the header don’t necessarily affect the separate editor widget.

If the palette isn’t aligned with your dark background, the OS light theme will produce a black editing text on a dark surface. To make the editor consistent, you need to control its palette explicitly.

Solution: delegate the editor and set its palette

The most direct fix is to customize the editor that gets created for editing. Override createEditor in a QStyledItemDelegate, set the colors you need, and install the delegate on the table so it applies everywhere.

from PySide6 import QtCore, QtGui, QtWidgets
class EditTintDelegate(QtWidgets.QStyledItemDelegate):
    def createEditor(self, host, opt, ix):
        editor_widget = super().createEditor(host, opt, ix)
        pal = editor_widget.palette()
        pal.setColor(QtGui.QPalette.Base, QtGui.QColor("#11375E"))
        pal.setColor(QtGui.QPalette.Text, QtCore.Qt.white)
        pal.setColor(QtGui.QPalette.Highlight, QtGui.QColor("#1b4f80"))
        pal.setColor(QtGui.QPalette.HighlightedText, QtCore.Qt.white)
        editor_widget.setPalette(pal)
        editor_widget.setStyleSheet("color: white;")
        return editor_widget
# apply to the whole table
view.setItemDelegate(EditTintDelegate(view))

This makes the in-place editor match the dark window, ensures the typing color is white, and keeps selections readable.

Why this approach works

The editor is its own widget, so styling it directly avoids theme-dependent surprises. By setting Base and Text you control the editor background and foreground. Adjusting Highlight and HighlightedText keeps selection legible. Because the delegate owns editor creation, the change is contained and applies consistently for every edited cell.

When to set the palette at the window level

If the whole dialog uses a dark scheme, configuring the palette for the top-level window can also make sense. Setting Window to your background and aligning Base with the same color or even QColorConstants.Transparent, then using white for WindowText, ButtonText and Text, creates a coherent baseline for inherited widgets. This approach addresses more than just the table editor and can reduce reliance on scattered QSS.

Takeaways

Editing in a QTableView spins up a real editor widget, so model roles and view stylesheets won’t guarantee readable text when themes change. Control the editor’s palette via a QStyledItemDelegate to get predictable colors, and consider defining the parent window palette to keep the whole UI visually consistent. This ensures your table remains legible in both dark and light environments and avoids theme-driven regressions.

The article is based on a question from StackOverflow by user2965433 and an answer by Ahrimann Steiner.