2026, Jan 07 05:00
Style PyQt5 QMenu Dropdowns Correctly: Use QMainWindow.menuBar() and Proper Stylesheet Scope
Learn why PyQt5 QMenu dropdowns ignore styles and how to fix them: set styles on QMainWindow, use menuBar(), and scope Qt Style Sheets correctly. See how.
Styling a QMenu dropdown in PyQt5 often feels unpredictable until you align two key pieces: how Qt applies style sheets and how QMainWindow manages its menu bar. If a QMenu ignores your CSS, it’s usually not about selector syntax but about ownership and where the style is set.
The setup that causes trouble
The following code builds a window with a custom QMenuBar on a central widget, attaches a QMenu with a QAction, and tries to style everything via a style sheet. The dropdown remains unstyled because of how parent/child relations and style sheet propagation work in Qt.
from PyQt5.QtWidgets import QApplication, QWidget, QMenuBar, QMenu, QAction, QVBoxLayout, QMainWindow
class MainFrame(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('demo')
self.resize(200, 200)
self.centralPane = QWidget()
self.rootLayout = QVBoxLayout()
self.topMenuBar = QMenuBar()
self.menuHelp = QMenu('Help')
self.topMenuBar.addMenu(self.menuHelp)
self.actRun = QAction('Action')
self.menuHelp.addAction(self.actRun)
self.rootLayout.addWidget(self.topMenuBar)
self.centralPane.setStyleSheet("""
QWidget {
background-color: #222;
color: #cfcfcf;
font-family: Roboto;
font-size: 14pt;
}
QMenuBar {
background-color: #222;
padding-top: 4px;
}
QMenuBar::item {
border-radius: 4px;
border-width: 0;
padding: 4px 8px;
}
QMenuBar::item:selected {
background-color: #777777;
}
QMenu, QAction {
background-color: red;
border-radius: 4px;
border-width: 0;
}
QMenu::item {
color: blue;
}
QMenu::item:selected {
background-color: aqua;
color: orange;
}
""")
self.centralPane.setLayout(self.rootLayout)
self.setCentralWidget(self.centralPane)
if __name__ == '__main__':
app = QApplication([])
win = MainFrame()
win.show()
app.exec_()
Why the dropdown ignores your styles
Qt Style Sheets apply down the parent/child hierarchy. A widget inherits styles only if it is a child of the widget on which the style sheet is set. In the example above, the style sheet is applied to the central widget, but the QMenu instance is a standalone object with no parent/child relationship to that widget. Adding a QMenu to a QMenuBar does not establish ownership. As a result, the dropdown menu does not inherit the style sheet.
There is another conceptual pitfall. QMainWindow already provides a built-in menu bar via menuBar(). Creating a separate QMenuBar and putting it into the central area bypasses the intended API and commonly leads to styling and behavior inconsistencies.
Finally, QAction is not a widget. It can be displayed by widgets like QMenu or QMenuBar, but it cannot be styled directly. Any selector that targets QAction will have no effect.
Make it work: scope the stylesheet to the right owner
The simplest fix is to apply the style sheet to an object that is an ancestor of the menu bar and the menus it hosts. In a QMainWindow-based application, that means setting the style sheet on the QMainWindow instance and using the native menuBar() API so the menu hierarchy remains within that window’s ownership. Qt will then propagate the styles to the dropdown.
There is also a global option. Applying the style to the entire application works, but it affects every widget in the process and is generally not desirable unless that’s your explicit goal.
QApplication.instance().setStyleSheet("""
...
""")
Corrected example
This version relies on QMainWindow.menuBar(), adds the menu via the provided API, and applies the style sheet to the window. The styling now reaches the QMenu as expected.
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('demo')
self.resize(200, 200)
content = QWidget()
layout = QVBoxLayout()
content.setLayout(layout)
mb = self.menuBar()
helpMenu = mb.addMenu('Help')
actionOne = helpMenu.addAction('Action')
self.setStyleSheet("""
QWidget {
background-color: #222;
color: #cfcfcf;
font-family: Roboto;
font-size: 14pt;
}
QMenuBar {
background-color: #222;
padding-top: 4px;
}
QMenuBar::item {
border-radius: 4px;
border-width: 0;
padding: 4px 8px;
}
QMenuBar::item:selected {
background-color: #777777;
}
QMenu, QAction {
background-color: red;
border-radius: 4px;
border-width: 0;
}
QMenu::item {
color: blue;
}
QMenu::item:selected {
background-color: aqua;
color: orange;
}
""")
self.setCentralWidget(content)
if __name__ == '__main__':
app = QApplication([])
w = MainWindow()
w.show()
app.exec()
When you draw your own title bar
If you have a borderless window with a custom title bar, you can still keep menu ownership correct. Use QMainWindow.setMenuWidget() to place your combined title/menu area in the title bar region, and if you manage layouts yourself, attach the bar to a layout with setMenuBar(). You can also merge the title bar and menu bar into a single widget and set it via setMenuWidget(). In all cases, remember that QActions are not widgets and don’t become children just because they are displayed; QMenuBar and QMenu don’t take ownership of the actions they show.
Why this matters
Qt’s styling is powerful but strictly scope-driven. Misplacing a stylesheet or bypassing QMainWindow’s menu API leads to “why doesn’t it style?” scenarios that are tricky to debug. Ensuring the menu structure lives under the styled owner keeps behavior predictable, prevents unrelated widgets from being affected, and avoids side effects across the application.
Practical takeaways
Rely on QMainWindow.menuBar() instead of embedding your own QMenuBar in the central area. Apply the style sheet to a widget that actually owns the UI elements you want to style; using the window is usually enough for menus and dropdowns, whereas the application-level style sheet should be reserved for cases where a global look is intended. Prefer the convenience overloads like QMenu.addAction() unless you need to reuse actions elsewhere. Avoid broad selectors like QWidget unless you clearly understand their impact on complex controls. Keep names idiomatic with class names starting uppercase, use super() without arguments in Python 3, and prefer app.exec() over the legacy exec_().
Following these rules ensures your QMenu and its dropdown style exactly as you expect, whether you use a standard window frame or a custom title bar.